diff --git a/.gitignore b/.gitignore index 65dc397..01c87d7 100644 --- a/.gitignore +++ b/.gitignore @@ -136,6 +136,8 @@ UpgradeLog*.htm App_Data/*.mdf App_Data/*.ldf +.vs/ + ############# ## Windows detritus ############# diff --git a/BakingLab/AppSettings.cpp b/BakingLab/AppSettings.cpp index 050597b..30ee488 100644 --- a/BakingLab/AppSettings.cpp +++ b/BakingLab/AppSettings.cpp @@ -1,931 +1,1067 @@ -#include -#include -#include "AppSettings.h" - -using namespace SampleFramework11; - -static const char* SunDirectionTypesLabels[2] = -{ - "Unit Vector", - "Horizontal Coordinate System", -}; - -static const char* SkyModesLabels[6] = -{ - "None", - "Procedural", - "Simple", - "Ennis", - "Grace Cathedral", - "Uffizi Cross", -}; - -static const char* LightUnitsLabels[4] = -{ - "Luminance", - "Illuminance", - "LuminousPower", - "EV100", -}; - -static const char* ExposureModesLabels[4] = -{ - "Manual (Simple)", - "Manual (SBS)", - "Manual (SOS)", - "Automatic", -}; - -static const char* FStopsLabels[23] = -{ - "f/1.8", - "f/2.0", - "f/2.2", - "f/2.5", - "f/2.8", - "f/3.2", - "f/3.5", - "f/4.0", - "f/4.5", - "f/5.0", - "f/5.6", - "f/6.3", - "f/7.1", - "f/8.0", - "f/9.0", - "f/10.0", - "f/11.0", - "f/13.0", - "f/14.0", - "f/16.0", - "f/18.0", - "f/20.0", - "f/22.0", -}; - -static const char* ISORatingsLabels[4] = -{ - "ISO100", - "ISO200", - "ISO400", - "ISO800", -}; - -static const char* ShutterSpeedsLabels[13] = -{ - "1s", - "1/2s", - "1/4s", - "1/8s", - "1/15s", - "1/30s", - "1/60s", - "1/125s", - "1/250s", - "1/500s", - "1/1000s", - "1/2000s", - "1/4000s", -}; - -static const char* ToneMappingModesLabels[5] = -{ - "Film Stock", - "Linear", - "ACES sRGB Monitor", - "Hejl 2015", - "Hable (Uncharted2)", -}; - -static const char* MSAAModesLabels[4] = -{ - "None", - "2x", - "4x", - "8x", -}; - -static const char* FilterTypesLabels[6] = -{ - "Box", - "Triangle", - "Gaussian", - "BlackmanHarris", - "Smoothstep", - "BSpline", -}; - -static const char* JitterModesLabels[5] = -{ - "None", - "Uniform2x", - "Hammersley4x", - "Hammersley8x", - "Hammersley16x", -}; - -static const char* SGDiffuseModesLabels[3] = -{ - "InnerProduct", - "Punctual", - "Fitted (Hill 16)", -}; - -static const char* SampleModesLabels[5] = -{ - "Random", - "Stratified", - "Hammersley", - "UniformGrid", - "CMJ", -}; - -static const char* BakeModesLabels[10] = -{ - "Diffuse", - "Half-Life 2", - "L1 SH", - "L2 SH", - "L1 H-basis", - "L2 H-basis", - "SG5", - "SG6", - "SG9", - "SG12", -}; - -static const char* SolveModesLabels[3] = -{ - "Ad-Hoc Projection", - "Least Squares", - "Non-Negative Least Squares", -}; - -static const char* ScenesLabels[3] = -{ - "Box", - "White Room", - "Sponza", -}; - -namespace AppSettings -{ - BoolSetting EnableSun; - BoolSetting SunAreaLightApproximation; - ColorSetting SunTintColor; - FloatSetting SunIntensityScale; - FloatSetting SunSize; - BoolSetting NormalizeSunIntensity; - SunDirectionTypesSetting SunDirType; - DirectionSetting SunDirection; - FloatSetting SunAzimuth; - FloatSetting SunElevation; - SkyModesSetting SkyMode; - ColorSetting SkyColor; - FloatSetting Turbidity; - ColorSetting GroundAlbedo; - BoolSetting EnableAreaLight; - ColorSetting AreaLightColor; - FloatSetting AreaLightIlluminance; - FloatSetting AreaLightLuminousPower; - FloatSetting AreaLightEV100; - LightUnitsSetting AreaLightUnits; - FloatSetting AreaLightIlluminanceDistance; - FloatSetting AreaLightSize; - FloatSetting AreaLightX; - FloatSetting AreaLightY; - FloatSetting AreaLightZ; - FloatSetting AreaLightShadowBias; - BoolSetting BakeDirectAreaLight; - BoolSetting EnableAreaLightShadows; - ExposureModesSetting ExposureMode; - FloatSetting ManualExposure; - FStopsSetting ApertureSize; - ISORatingsSetting ISORating; - ShutterSpeedsSetting ShutterSpeed; - FloatSetting FilmSize; - FloatSetting FocalLength; - FloatSetting FocusDistance; - IntSetting NumBlades; - BoolSetting EnableDOF; - FloatSetting KeyValue; - FloatSetting AdaptationRate; - FloatSetting ApertureFNumber; - FloatSetting ApertureWidth; - FloatSetting ShutterSpeedValue; - FloatSetting ISO; - FloatSetting BokehPolygonAmount; - ToneMappingModesSetting ToneMappingMode; - FloatSetting WhitePoint_Hejl; - FloatSetting ShoulderStrength; - FloatSetting LinearStrength; - FloatSetting LinearAngle; - FloatSetting ToeStrength; - FloatSetting WhitePoint_Hable; - MSAAModesSetting MSAAMode; - FilterTypesSetting FilterType; - FloatSetting FilterSize; - FloatSetting GaussianSigma; - BoolSetting EnableTemporalAA; - JitterModesSetting JitterMode; - FloatSetting JitterScale; - SGDiffuseModesSetting SGDiffuseMode; - BoolSetting UseASGWarp; - IntSetting LightMapResolution; - IntSetting NumBakeSamples; - SampleModesSetting BakeSampleMode; - IntSetting MaxBakePathLength; - IntSetting BakeRussianRouletteDepth; - FloatSetting BakeRussianRouletteProbability; - BakeModesSetting BakeMode; - SolveModesSetting SolveMode; - ScenesSetting CurrentScene; - BoolSetting EnableDiffuse; - BoolSetting EnableSpecular; - BoolSetting EnableDirectLighting; - BoolSetting EnableIndirectLighting; - BoolSetting EnableIndirectDiffuse; - BoolSetting EnableIndirectSpecular; - BoolSetting EnableAlbedoMaps; - BoolSetting EnableNormalMaps; - FloatSetting NormalMapIntensity; - FloatSetting DiffuseAlbedoScale; - FloatSetting RoughnessScale; - BoolSetting ShowGroundTruth; - IntSetting NumRenderSamples; - SampleModesSetting RenderSampleMode; - IntSetting MaxRenderPathLength; - IntSetting RenderRussianRouletteDepth; - FloatSetting RenderRussianRouletteProbability; - BoolSetting EnableRenderBounceSpecular; - FloatSetting BloomExposure; - FloatSetting BloomMagnitude; - FloatSetting BloomBlurSigma; - BoolSetting EnableLuminancePicker; - BoolSetting ShowBakeDataVisualizer; - BoolSetting ViewIndirectSpecular; - Button SaveLightSettings; - Button LoadLightSettings; - Button SaveEXRScreenshot; - BoolSetting ShowSunIntensity; - - ConstantBuffer CBuffer; - - void Initialize(ID3D11Device* device) - { - TwBar* tweakBar = Settings.TweakBar(); - - EnableSun.Initialize(tweakBar, "EnableSun", "Sun Light", "Enable Sun", "Enables the sun light", true); - Settings.AddSetting(&EnableSun); - - SunAreaLightApproximation.Initialize(tweakBar, "SunAreaLightApproximation", "Sun Light", "Sun Area Light Approximation", "Controls whether the sun is treated as a disc area light in the real-time shader", true); - Settings.AddSetting(&SunAreaLightApproximation); - - SunTintColor.Initialize(tweakBar, "SunTintColor", "Sun Light", "Sun Tint Color", "The color of the sun", Float3(1.0000f, 1.0000f, 1.0000f), false, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ColorUnit::None); - Settings.AddSetting(&SunTintColor); - - SunIntensityScale.Initialize(tweakBar, "SunIntensityScale", "Sun Light", "Sun Intensity Scale", "Scale the intensity of the sun", 1.0000f, 0.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&SunIntensityScale); - - SunSize.Initialize(tweakBar, "SunSize", "Sun Light", "Sun Size", "Angular radius of the sun in degrees", 0.2700f, 0.0100f, 340282300000000000000000000000000000000.0000f, 0.0010f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&SunSize); - - NormalizeSunIntensity.Initialize(tweakBar, "NormalizeSunIntensity", "Sun Light", "Normalize Sun Intensity", "", false); - Settings.AddSetting(&NormalizeSunIntensity); - - SunDirType.Initialize(tweakBar, "SunDirType", "Sun Light", "Sun Dir Type", "Input direction type for the sun", SunDirectionTypes::HorizontalCoordSystem, 2, SunDirectionTypesLabels); - Settings.AddSetting(&SunDirType); - - SunDirection.Initialize(tweakBar, "SunDirection", "Sun Light", "Sun Direction", "Director of the sun", Float3(-0.7500f, 0.9770f, -0.4000f)); - Settings.AddSetting(&SunDirection); - - SunAzimuth.Initialize(tweakBar, "SunAzimuth", "Sun Light", "Sun Azimuth", "Angle around the horizon", 0.0000f, 0.0000f, 360.0000f, 0.1000f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&SunAzimuth); - - SunElevation.Initialize(tweakBar, "SunElevation", "Sun Light", "Sun Elevation", "Elevation of sun from ground. 0 degrees is aligned on the horizon while 90 degrees is directly overhead", 0.0000f, 0.0000f, 90.0000f, 0.1000f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&SunElevation); - - SkyMode.Initialize(tweakBar, "SkyMode", "Sky", "Sky Mode", "Controls the sky used for GI baking and background rendering", SkyModes::Procedural, 6, SkyModesLabels); - Settings.AddSetting(&SkyMode); - - SkyColor.Initialize(tweakBar, "SkyColor", "Sky", "Sky Color", "The color of the simple sky", Float3(1400.0000f, 3500.0000f, 7000.0000f), true, 0.0000f, 1000000.0000f, 0.1000f, ColorUnit::Luminance); - Settings.AddSetting(&SkyColor); - - Turbidity.Initialize(tweakBar, "Turbidity", "Sky", "Turbidity", "", 2.0000f, 1.0000f, 10.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&Turbidity); - - GroundAlbedo.Initialize(tweakBar, "GroundAlbedo", "Sky", "Ground Albedo", "", Float3(0.5000f, 0.5000f, 0.5000f), false, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ColorUnit::None); - Settings.AddSetting(&GroundAlbedo); - - EnableAreaLight.Initialize(tweakBar, "EnableAreaLight", "Area Light", "Enable Area Light", "Enables the area light during baking and ground truth rendering", false); - Settings.AddSetting(&EnableAreaLight); - - AreaLightColor.Initialize(tweakBar, "AreaLightColor", "Area Light", "Color", "The color of the area light", Float3(1000000.0000f, 1000000.0000f, 1000000.0000f), true, 0.0000f, 340282300000000000000000000000000000000.0000f, 0.1000f, ColorUnit::Luminance); - Settings.AddSetting(&AreaLightColor); - - AreaLightIlluminance.Initialize(tweakBar, "AreaLightIlluminance", "Area Light", "Color Intensity (lux)", "", 1.0000f, 0.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&AreaLightIlluminance); - AreaLightIlluminance.SetVisible(false); - - AreaLightLuminousPower.Initialize(tweakBar, "AreaLightLuminousPower", "Area Light", "Color Intensity (lm)", "", 1.0000f, 0.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&AreaLightLuminousPower); - AreaLightLuminousPower.SetVisible(false); - - AreaLightEV100.Initialize(tweakBar, "AreaLightEV100", "Area Light", "Color Intensity (EV100)", "", 0.0000f, -64.0000f, 64.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&AreaLightEV100); - AreaLightEV100.SetVisible(false); - - AreaLightUnits.Initialize(tweakBar, "AreaLightUnits", "Area Light", "Units", "", LightUnits::Luminance, 4, LightUnitsLabels); - Settings.AddSetting(&AreaLightUnits); - - AreaLightIlluminanceDistance.Initialize(tweakBar, "AreaLightIlluminanceDistance", "Area Light", "Illuminance Distance", "", 10.0000f, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&AreaLightIlluminanceDistance); - AreaLightIlluminanceDistance.SetVisible(false); - - AreaLightSize.Initialize(tweakBar, "AreaLightSize", "Area Light", "Size", "The radius of the area light", 0.5000f, 0.0100f, 10.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&AreaLightSize); - - AreaLightX.Initialize(tweakBar, "AreaLightX", "Area Light", "Position X", "The X coordinate of the area light", 0.0000f, -100.0000f, 100.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&AreaLightX); - - AreaLightY.Initialize(tweakBar, "AreaLightY", "Area Light", "Position Y", "The Y coordinate of the area light", 5.0000f, -100.0000f, 100.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&AreaLightY); - - AreaLightZ.Initialize(tweakBar, "AreaLightZ", "Area Light", "Position Z", "The Z coordinate of the area light", 0.0000f, -100.0000f, 100.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&AreaLightZ); - - AreaLightShadowBias.Initialize(tweakBar, "AreaLightShadowBias", "Area Light", "Shadow Bias", "", 0.0010f, 0.0000f, 1.0000f, 0.0010f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&AreaLightShadowBias); - - BakeDirectAreaLight.Initialize(tweakBar, "BakeDirectAreaLight", "Area Light", "Bake Direct Area Light", "Bakes the direct contribution from the area light into the light map", false); - Settings.AddSetting(&BakeDirectAreaLight); - - EnableAreaLightShadows.Initialize(tweakBar, "EnableAreaLightShadows", "Area Light", "Enable Area Light Shadows", "", true); - Settings.AddSetting(&EnableAreaLightShadows); - - ExposureMode.Initialize(tweakBar, "ExposureMode", "Camera Controls", "Exposure Mode", "Specifies how exposure should be controled", ExposureModes::Manual_SBS, 4, ExposureModesLabels); - Settings.AddSetting(&ExposureMode); - - ManualExposure.Initialize(tweakBar, "ManualExposure", "Camera Controls", "Manual Exposure", "Manual exposure value when auto-exposure is disabled", -16.0000f, -32.0000f, 32.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&ManualExposure); - - ApertureSize.Initialize(tweakBar, "ApertureSize", "Camera Controls", "Aperture", "", FStops::FStop16Point0, 23, FStopsLabels); - Settings.AddSetting(&ApertureSize); - - ISORating.Initialize(tweakBar, "ISORating", "Camera Controls", "ISO Rating", "", ISORatings::ISO100, 4, ISORatingsLabels); - Settings.AddSetting(&ISORating); - - ShutterSpeed.Initialize(tweakBar, "ShutterSpeed", "Camera Controls", "Shutter Speed", "", ShutterSpeeds::ShutterSpeed1Over125, 13, ShutterSpeedsLabels); - Settings.AddSetting(&ShutterSpeed); - - FilmSize.Initialize(tweakBar, "FilmSize", "Camera Controls", "Film Size(mm)", "", 35.0000f, 1.0000f, 100.0000f, 0.1000f, ConversionMode::None, 0.0010f); - Settings.AddSetting(&FilmSize); - - FocalLength.Initialize(tweakBar, "FocalLength", "Camera Controls", "Focal Length(mm)", "", 35.0000f, 1.0000f, 200.0000f, 0.1000f, ConversionMode::None, 0.0010f); - Settings.AddSetting(&FocalLength); - - FocusDistance.Initialize(tweakBar, "FocusDistance", "Camera Controls", "Focus Distance", "", 10.0000f, 1.0000f, 100.0000f, 0.1000f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&FocusDistance); - - NumBlades.Initialize(tweakBar, "NumBlades", "Camera Controls", "Num Aperture Blades", "", 5, 5, 9); - Settings.AddSetting(&NumBlades); - - EnableDOF.Initialize(tweakBar, "EnableDOF", "Camera Controls", "Enable DOF", "", false); - Settings.AddSetting(&EnableDOF); - - KeyValue.Initialize(tweakBar, "KeyValue", "Camera Controls", "Auto-Exposure Key Value", "Parameter that biases the result of the auto-exposure pass", 0.1150f, 0.0000f, 0.5000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&KeyValue); - - AdaptationRate.Initialize(tweakBar, "AdaptationRate", "Camera Controls", "Adaptation Rate", "Controls how quickly auto-exposure adapts to changes in scene brightness", 0.5000f, 0.0000f, 4.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&AdaptationRate); - - ApertureFNumber.Initialize(tweakBar, "ApertureFNumber", "Camera Controls", "Aperture FNumber", "", 0.0000f, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&ApertureFNumber); - ApertureFNumber.SetVisible(false); - ApertureFNumber.SetEditable(false); - - ApertureWidth.Initialize(tweakBar, "ApertureWidth", "Camera Controls", "Aperture Width", "", 0.0000f, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&ApertureWidth); - ApertureWidth.SetVisible(false); - ApertureWidth.SetEditable(false); - - ShutterSpeedValue.Initialize(tweakBar, "ShutterSpeedValue", "Camera Controls", "Shutter Speed Value", "", 0.0000f, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&ShutterSpeedValue); - ShutterSpeedValue.SetVisible(false); - ShutterSpeedValue.SetEditable(false); - - ISO.Initialize(tweakBar, "ISO", "Camera Controls", "ISO", "", 0.0000f, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&ISO); - ISO.SetVisible(false); - ISO.SetEditable(false); - - BokehPolygonAmount.Initialize(tweakBar, "BokehPolygonAmount", "Camera Controls", "Bokeh Polygon Amount", "", 0.0000f, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&BokehPolygonAmount); - BokehPolygonAmount.SetVisible(false); - BokehPolygonAmount.SetEditable(false); - - ToneMappingMode.Initialize(tweakBar, "ToneMappingMode", "Tone Mapping", "Tone Mapping Operator", "", ToneMappingModes::ACES, 5, ToneMappingModesLabels); - Settings.AddSetting(&ToneMappingMode); - - WhitePoint_Hejl.Initialize(tweakBar, "WhitePoint_Hejl", "Tone Mapping", "White Point (Hejl2015)", "", 1.0000f, 0.0100f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&WhitePoint_Hejl); - - ShoulderStrength.Initialize(tweakBar, "ShoulderStrength", "Tone Mapping", "Shoulder Strength", "", 4.0000f, 0.0100f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&ShoulderStrength); - - LinearStrength.Initialize(tweakBar, "LinearStrength", "Tone Mapping", "Linear Strength", "", 5.0000f, 0.0100f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&LinearStrength); - - LinearAngle.Initialize(tweakBar, "LinearAngle", "Tone Mapping", "Linear Angle", "", 0.1200f, 0.0100f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&LinearAngle); - - ToeStrength.Initialize(tweakBar, "ToeStrength", "Tone Mapping", "Toe Strength", "", 13.0000f, 0.0100f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&ToeStrength); - - WhitePoint_Hable.Initialize(tweakBar, "WhitePoint_Hable", "Tone Mapping", "White Point (Hable)", "", 6.0000f, 0.0100f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&WhitePoint_Hable); - - MSAAMode.Initialize(tweakBar, "MSAAMode", "Anti Aliasing", "MSAAMode", "", MSAAModes::MSAA4x, 4, MSAAModesLabels); - Settings.AddSetting(&MSAAMode); - - FilterType.Initialize(tweakBar, "FilterType", "Anti Aliasing", "Filter Type", "", FilterTypes::Smoothstep, 6, FilterTypesLabels); - Settings.AddSetting(&FilterType); - - FilterSize.Initialize(tweakBar, "FilterSize", "Anti Aliasing", "Filter Size", "", 2.0000f, 0.0000f, 6.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&FilterSize); - - GaussianSigma.Initialize(tweakBar, "GaussianSigma", "Anti Aliasing", "Gaussian Sigma", "", 0.5000f, 0.0100f, 1.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&GaussianSigma); - - EnableTemporalAA.Initialize(tweakBar, "EnableTemporalAA", "Anti Aliasing", "Enable Temporal AA", "", true); - Settings.AddSetting(&EnableTemporalAA); - - JitterMode.Initialize(tweakBar, "JitterMode", "Anti Aliasing", "Jitter Mode", "", JitterModes::Hammersley4x, 5, JitterModesLabels); - Settings.AddSetting(&JitterMode); - - JitterScale.Initialize(tweakBar, "JitterScale", "Anti Aliasing", "Jitter Scale", "", 1.0000f, 0.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&JitterScale); - - SGDiffuseMode.Initialize(tweakBar, "SGDiffuseMode", "SG Settings", "SG Diffuse Mode", "", SGDiffuseModes::Fitted, 3, SGDiffuseModesLabels); - Settings.AddSetting(&SGDiffuseMode); - - UseASGWarp.Initialize(tweakBar, "UseASGWarp", "SG Settings", "Use ASG Warp", "", true); - Settings.AddSetting(&UseASGWarp); - - LightMapResolution.Initialize(tweakBar, "LightMapResolution", "Baking", "Light Map Resolution", "The texture resolution of the light map", 256, 64, 4096); - Settings.AddSetting(&LightMapResolution); - - NumBakeSamples.Initialize(tweakBar, "NumBakeSamples", "Baking", "Sqrt Num Samples", "The square root of the number of sample rays to use for baking GI", 25, 1, 100); - Settings.AddSetting(&NumBakeSamples); - - BakeSampleMode.Initialize(tweakBar, "BakeSampleMode", "Baking", "Sample Mode", "", SampleModes::CMJ, 5, SampleModesLabels); - Settings.AddSetting(&BakeSampleMode); - - MaxBakePathLength.Initialize(tweakBar, "MaxBakePathLength", "Baking", "Max Bake Path Length", "Maximum path length (bounces + 2) to use for baking GI (set to -1 for infinite)", -1, -1, 2147483647); - Settings.AddSetting(&MaxBakePathLength); - - BakeRussianRouletteDepth.Initialize(tweakBar, "BakeRussianRouletteDepth", "Baking", "Russian Roullette Depth", "Path length at which Russian roulette kicks in (-1 to disable)", 4, -1, 2147483647); - Settings.AddSetting(&BakeRussianRouletteDepth); - - BakeRussianRouletteProbability.Initialize(tweakBar, "BakeRussianRouletteProbability", "Baking", "Russian Roullette Probability", "Maximum probability for continuing when Russian roulette is used", 0.5000f, 0.0000f, 1.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&BakeRussianRouletteProbability); - - BakeMode.Initialize(tweakBar, "BakeMode", "Baking", "Bake Mode", "", BakeModes::SG9, 10, BakeModesLabels); - Settings.AddSetting(&BakeMode); - - SolveMode.Initialize(tweakBar, "SolveMode", "Baking", "Solve Mode", "", SolveModes::NNLS, 3, SolveModesLabels); - Settings.AddSetting(&SolveMode); - - CurrentScene.Initialize(tweakBar, "CurrentScene", "Scene", "Current Scene", "", Scenes::Box, 3, ScenesLabels); - Settings.AddSetting(&CurrentScene); - - EnableDiffuse.Initialize(tweakBar, "EnableDiffuse", "Scene", "Enable Diffuse", "Enables diffuse lighting", true); - Settings.AddSetting(&EnableDiffuse); - - EnableSpecular.Initialize(tweakBar, "EnableSpecular", "Scene", "Enable Specular", "Enables specular lighting", true); - Settings.AddSetting(&EnableSpecular); - - EnableDirectLighting.Initialize(tweakBar, "EnableDirectLighting", "Scene", "Enable Direct Lighting", "Enables direct lighting", true); - Settings.AddSetting(&EnableDirectLighting); - - EnableIndirectLighting.Initialize(tweakBar, "EnableIndirectLighting", "Scene", "Enable Indirect Lighting", "Enables indirect lighting", true); - Settings.AddSetting(&EnableIndirectLighting); - - EnableIndirectDiffuse.Initialize(tweakBar, "EnableIndirectDiffuse", "Scene", "Enable Indirect Diffuse", "Enables indirect diffuse lighting", true); - Settings.AddSetting(&EnableIndirectDiffuse); - - EnableIndirectSpecular.Initialize(tweakBar, "EnableIndirectSpecular", "Scene", "Enable Indirect Specular", "Enables indirect specular lighting", true); - Settings.AddSetting(&EnableIndirectSpecular); - - EnableAlbedoMaps.Initialize(tweakBar, "EnableAlbedoMaps", "Scene", "Enable Albedo Maps", "Enables albedo maps", true); - Settings.AddSetting(&EnableAlbedoMaps); - - EnableNormalMaps.Initialize(tweakBar, "EnableNormalMaps", "Scene", "Enable Normal Maps", "Enables normal maps", true); - Settings.AddSetting(&EnableNormalMaps); - - NormalMapIntensity.Initialize(tweakBar, "NormalMapIntensity", "Scene", "Normal Map Intensity", "Intensity of the normal map", 0.5000f, 0.0000f, 1.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&NormalMapIntensity); - - DiffuseAlbedoScale.Initialize(tweakBar, "DiffuseAlbedoScale", "Scene", "Diffuse Albedo Scale", "Global scale applied to all material diffuse albedo values", 0.5000f, 0.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&DiffuseAlbedoScale); - - RoughnessScale.Initialize(tweakBar, "RoughnessScale", "Scene", "Specular Roughness Scale", "Global scale applied to all material roughness values", 2.0000f, 0.0100f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&RoughnessScale); - - ShowGroundTruth.Initialize(tweakBar, "ShowGroundTruth", "Ground Truth", "Show Ground Truth", "If enabled, shows a ground truth image rendered on the CPU", false); - Settings.AddSetting(&ShowGroundTruth); - - NumRenderSamples.Initialize(tweakBar, "NumRenderSamples", "Ground Truth", "Sqrt Num Samples", "The square root of the number of per-pixel sample rays to use for ground truth rendering", 4, 1, 100); - Settings.AddSetting(&NumRenderSamples); - - RenderSampleMode.Initialize(tweakBar, "RenderSampleMode", "Ground Truth", "Sample Mode", "", SampleModes::CMJ, 5, SampleModesLabels); - Settings.AddSetting(&RenderSampleMode); - - MaxRenderPathLength.Initialize(tweakBar, "MaxRenderPathLength", "Ground Truth", "Max Path Length", "Maximum path length (bounces) to use for ground truth rendering (set to -1 for infinite)", -1, -1, 2147483647); - Settings.AddSetting(&MaxRenderPathLength); - - RenderRussianRouletteDepth.Initialize(tweakBar, "RenderRussianRouletteDepth", "Ground Truth", "Russian Roullette Depth", "Path length at which Russian roulette kicks in (-1 to disable)", 4, -1, 2147483647); - Settings.AddSetting(&RenderRussianRouletteDepth); - - RenderRussianRouletteProbability.Initialize(tweakBar, "RenderRussianRouletteProbability", "Ground Truth", "Russian Roullette Probability", "Maximum probability for continuing when Russian roulette is used", 0.5000f, 0.0000f, 1.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&RenderRussianRouletteProbability); - - EnableRenderBounceSpecular.Initialize(tweakBar, "EnableRenderBounceSpecular", "Ground Truth", "Enable Bounce Specular", "Enables specular calculations after the first hit", false); - Settings.AddSetting(&EnableRenderBounceSpecular); - - BloomExposure.Initialize(tweakBar, "BloomExposure", "Post Processing", "Bloom Exposure Offset", "Exposure offset applied to generate the input of the bloom pass", -4.0000f, -10.0000f, 0.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&BloomExposure); - - BloomMagnitude.Initialize(tweakBar, "BloomMagnitude", "Post Processing", "Bloom Magnitude", "Scale factor applied to the bloom results when combined with tone-mapped result", 1.0000f, 0.0000f, 2.0000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&BloomMagnitude); - - BloomBlurSigma.Initialize(tweakBar, "BloomBlurSigma", "Post Processing", "Bloom Blur Sigma", "Sigma parameter of the Gaussian filter used in the bloom pass", 2.5000f, 0.5000f, 2.5000f, 0.0100f, ConversionMode::None, 1.0000f); - Settings.AddSetting(&BloomBlurSigma); - - EnableLuminancePicker.Initialize(tweakBar, "EnableLuminancePicker", "Debug", "Enable Luminance Picker", "", false); - Settings.AddSetting(&EnableLuminancePicker); - - ShowBakeDataVisualizer.Initialize(tweakBar, "ShowBakeDataVisualizer", "Debug", "Show Bake Data Visualizer", "", false); - Settings.AddSetting(&ShowBakeDataVisualizer); - - ViewIndirectSpecular.Initialize(tweakBar, "ViewIndirectSpecular", "Debug", "View Indirect Specular", "", false); - Settings.AddSetting(&ViewIndirectSpecular); - - SaveLightSettings.Initialize(tweakBar, "SaveLightSettings", "Debug", "Save Light Settings", "Saves the lighting settings to a file"); - Settings.AddSetting(&SaveLightSettings); - - LoadLightSettings.Initialize(tweakBar, "LoadLightSettings", "Debug", "Load Light Settings", "Loads the lighting settings from a file"); - Settings.AddSetting(&LoadLightSettings); - - SaveEXRScreenshot.Initialize(tweakBar, "SaveEXRScreenshot", "Debug", "Save EXR Screenshot", "Captures the current screen image in EXR format"); - Settings.AddSetting(&SaveEXRScreenshot); - - ShowSunIntensity.Initialize(tweakBar, "ShowSunIntensity", "Debug", "Show Sun Intensity", "", false); - Settings.AddSetting(&ShowSunIntensity); - - TwHelper::SetOpened(tweakBar, "Sun Light", true); - - TwHelper::SetOpened(tweakBar, "Sky", true); - - TwHelper::SetOpened(tweakBar, "Area Light", false); - - TwHelper::SetOpened(tweakBar, "Camera Controls", false); - - TwHelper::SetOpened(tweakBar, "Tone Mapping", false); - - TwHelper::SetOpened(tweakBar, "Anti Aliasing", false); - - TwHelper::SetOpened(tweakBar, "SG Settings", false); - - TwHelper::SetOpened(tweakBar, "Baking", false); - - TwHelper::SetOpened(tweakBar, "Scene", false); - - TwHelper::SetOpened(tweakBar, "Ground Truth", false); - - TwHelper::SetOpened(tweakBar, "Post Processing", false); - - TwHelper::SetOpened(tweakBar, "Debug", false); - - CBuffer.Initialize(device); - } - - void Update() - { - ApertureFNumber.SetValue(ApertureFNumber_()); - ApertureWidth.SetValue(ApertureWidth_()); - ShutterSpeedValue.SetValue(ShutterSpeedValue_()); - ISO.SetValue(ISO_()); - BokehPolygonAmount.SetValue(BokehPolygonAmount_()); - } - - void UpdateCBuffer(ID3D11DeviceContext* context) - { - CBuffer.Data.EnableSun = EnableSun; - CBuffer.Data.SunAreaLightApproximation = SunAreaLightApproximation; - CBuffer.Data.SunTintColor = SunTintColor; - CBuffer.Data.SunIntensityScale = SunIntensityScale; - CBuffer.Data.SunSize = SunSize; - CBuffer.Data.SunDirType = SunDirType; - CBuffer.Data.SunDirection = SunDirection; - CBuffer.Data.SunAzimuth = SunAzimuth; - CBuffer.Data.SunElevation = SunElevation; - CBuffer.Data.EnableAreaLight = EnableAreaLight; - CBuffer.Data.AreaLightColor = AreaLightColor; - CBuffer.Data.AreaLightSize = AreaLightSize; - CBuffer.Data.AreaLightX = AreaLightX; - CBuffer.Data.AreaLightY = AreaLightY; - CBuffer.Data.AreaLightZ = AreaLightZ; - CBuffer.Data.AreaLightShadowBias = AreaLightShadowBias; - CBuffer.Data.BakeDirectAreaLight = BakeDirectAreaLight; - CBuffer.Data.EnableAreaLightShadows = EnableAreaLightShadows; - CBuffer.Data.ExposureMode = ExposureMode; - CBuffer.Data.ManualExposure = ManualExposure; - CBuffer.Data.FilmSize = FilmSize; - CBuffer.Data.FocalLength = FocalLength; - CBuffer.Data.FocusDistance = FocusDistance; - CBuffer.Data.NumBlades = NumBlades; - CBuffer.Data.KeyValue = KeyValue; - CBuffer.Data.AdaptationRate = AdaptationRate; - CBuffer.Data.ApertureFNumber = ApertureFNumber; - CBuffer.Data.ApertureWidth = ApertureWidth; - CBuffer.Data.ShutterSpeedValue = ShutterSpeedValue; - CBuffer.Data.ISO = ISO; - CBuffer.Data.BokehPolygonAmount = BokehPolygonAmount; - CBuffer.Data.ToneMappingMode = ToneMappingMode; - CBuffer.Data.WhitePoint_Hejl = WhitePoint_Hejl; - CBuffer.Data.ShoulderStrength = ShoulderStrength; - CBuffer.Data.LinearStrength = LinearStrength; - CBuffer.Data.LinearAngle = LinearAngle; - CBuffer.Data.ToeStrength = ToeStrength; - CBuffer.Data.WhitePoint_Hable = WhitePoint_Hable; - CBuffer.Data.MSAAMode = MSAAMode; - CBuffer.Data.FilterType = FilterType; - CBuffer.Data.FilterSize = FilterSize; - CBuffer.Data.GaussianSigma = GaussianSigma; - CBuffer.Data.SGDiffuseMode = SGDiffuseMode; - CBuffer.Data.UseASGWarp = UseASGWarp; - CBuffer.Data.LightMapResolution = LightMapResolution; - CBuffer.Data.BakeMode = BakeMode; - CBuffer.Data.SolveMode = SolveMode; - CBuffer.Data.EnableDiffuse = EnableDiffuse; - CBuffer.Data.EnableSpecular = EnableSpecular; - CBuffer.Data.EnableDirectLighting = EnableDirectLighting; - CBuffer.Data.EnableIndirectLighting = EnableIndirectLighting; - CBuffer.Data.EnableIndirectDiffuse = EnableIndirectDiffuse; - CBuffer.Data.EnableIndirectSpecular = EnableIndirectSpecular; - CBuffer.Data.EnableAlbedoMaps = EnableAlbedoMaps; - CBuffer.Data.EnableNormalMaps = EnableNormalMaps; - CBuffer.Data.NormalMapIntensity = NormalMapIntensity; - CBuffer.Data.DiffuseAlbedoScale = DiffuseAlbedoScale; - CBuffer.Data.RoughnessScale = RoughnessScale; - CBuffer.Data.BloomExposure = BloomExposure; - CBuffer.Data.BloomMagnitude = BloomMagnitude; - CBuffer.Data.BloomBlurSigma = BloomBlurSigma; - CBuffer.Data.ViewIndirectSpecular = ViewIndirectSpecular; - - CBuffer.ApplyChanges(context); - CBuffer.SetVS(context, 7); - CBuffer.SetHS(context, 7); - CBuffer.SetDS(context, 7); - CBuffer.SetGS(context, 7); - CBuffer.SetPS(context, 7); - CBuffer.SetCS(context, 7); - } -} - -// ================================================================================================ - -#include -#include -#include - -namespace AppSettings -{ - // Returns the result of performing a irradiance/illuminance integral over the portion - // of the hemisphere covered by a region with angular radius = theta - static float IlluminanceIntegral(float theta) - { - float cosTheta = std::cos(theta); - return Pi * (1.0f - (cosTheta * cosTheta)); - } - - Float3 SunLuminance(bool& cached) - { - Float3 sunDirection = AppSettings::SunDirection; - sunDirection.y = Saturate(sunDirection.y); - sunDirection = Float3::Normalize(sunDirection); - const float turbidity = Clamp(AppSettings::Turbidity.Value(), 1.0f, 32.0f); - const float intensityScale = AppSettings::SunIntensityScale; - const Float3 tintColor = AppSettings::SunTintColor; - const bool32 normalizeIntensity = AppSettings::NormalizeSunIntensity; - const float sunSize = AppSettings::SunSize; - - static float turbidityCache = 2.0f; - static Float3 sunDirectionCache = Float3(-0.579149902f, 0.754439294f, -0.308879942f); - static Float3 luminanceCache = Float3(1.61212531e+009f, 1.36822630e+009f, 1.07235315e+009f) * FP16Scale; - static Float3 sunTintCache = Float3(1.0f, 1.0f, 1.0f); - static float sunIntensityCache = 1.0f; - static bool32 normalizeCache = false; - static float sunSizeCache = AppSettings::BaseSunSize; - - if(turbidityCache == turbidity && sunDirection == sunDirectionCache - && intensityScale == sunIntensityCache && tintColor == sunTintCache - && normalizeCache == normalizeIntensity && sunSize == sunSizeCache) - { - cached = true; - return luminanceCache; - } - - cached = false; - - float thetaS = std::acos(1.0f - sunDirection.y); - float elevation = Pi_2 - thetaS; - - // Get the sun's luminance, then apply tint and scale factors - Float3 sunLuminance; - - // For now, we'll compute an average luminance value from Hosek solar radiance model, even though - // we could compute illuminance directly while we're sampling the disk - SampledSpectrum groundAlbedoSpectrum = SampledSpectrum::FromRGB(GroundAlbedo); - SampledSpectrum solarRadiance; - - const uint64 NumDiscSamples = 8; - for(uint64 x = 0; x < NumDiscSamples; ++x) - { - for(uint64 y = 0; y < NumDiscSamples; ++y) - { - float u = (x + 0.5f) / NumDiscSamples; - float v = (y + 0.5f) / NumDiscSamples; - Float2 discSamplePos = SquareToConcentricDiskMapping(u, v); - - float theta = elevation + discSamplePos.y * DegToRad(AppSettings::BaseSunSize); - float gamma = discSamplePos.x * DegToRad(AppSettings::BaseSunSize); - - for(int32 i = 0; i < NumSpectralSamples; ++i) - { - ArHosekSkyModelState* skyState = arhosekskymodelstate_alloc_init(elevation, turbidity, groundAlbedoSpectrum[i]); - float wavelength = Lerp(float(SampledLambdaStart), float(SampledLambdaEnd), i / float(NumSpectralSamples)); - - solarRadiance[i] = float(arhosekskymodel_solar_radiance(skyState, theta, gamma, wavelength)); - - arhosekskymodelstate_free(skyState); - skyState = nullptr; - } - - Float3 sampleRadiance = solarRadiance.ToRGB() * FP16Scale; - sunLuminance += sampleRadiance; - } - } - - // Account for luminous efficiency, coordinate system scaling, and sample averaging - sunLuminance *= 683.0f * 100.0f * (1.0f / NumDiscSamples) * (1.0f / NumDiscSamples); - - sunLuminance = sunLuminance * tintColor; - sunLuminance = sunLuminance * intensityScale; - - if(normalizeIntensity) - { - // Normalize so that the intensity stays the same even when the sun is bigger or smaller - const float baseIntegral = IlluminanceIntegral(DegToRad(AppSettings::BaseSunSize)); - const float currIntegral = IlluminanceIntegral(DegToRad(AppSettings::SunSize)); - sunLuminance *= (baseIntegral / currIntegral); - } - - turbidityCache = turbidity; - sunDirectionCache = sunDirection; - luminanceCache = sunLuminance; - sunIntensityCache = intensityScale; - sunTintCache = tintColor; - normalizeCache = normalizeIntensity; - sunSizeCache = sunSize; - - return sunLuminance; - } - - Float3 SunLuminance() - { - bool cached = false; - return SunLuminance(cached); - } - - Float3 SunIlluminance() - { - Float3 sunLuminance = SunLuminance(); - - // Compute partial integral over the hemisphere in order to compute illuminance - float theta = DegToRad(AppSettings::SunSize); - float integralFactor = IlluminanceIntegral(theta); - - return sunLuminance * integralFactor; - } - - static void UpdateAreaLightUnits() - { - static LightUnits prevUnits = AreaLightUnits; - const LightUnits currUnits = AreaLightUnits; - - const float size = AreaLightSize; - const float distance = AreaLightIlluminanceDistance; - - // Compute the luminance from our currently active unit - float luminance = AreaLightColor.Intensity(); - if(prevUnits == LightUnits::Illuminance) - { - float illuminance = AreaLightIlluminance; - float angularRadius = std::atan2(size, distance); - float integralFactor = IlluminanceIntegral(angularRadius); - luminance = illuminance / integralFactor; - } - else if(prevUnits == LightUnits::LuminousPower) - { - float luminousPower = AreaLightLuminousPower; - luminance = luminousPower / (4 * size * size * Pi * Pi); - } - else if(prevUnits == LightUnits::EV100) - { - float ev100 = AreaLightEV100; - luminance = std::pow(2.0f, ev100 - 3.0f); - } - - // Set the new luminance onto the color - AreaLightColor.SetIntensity(luminance); - - // Update the other units - float angularRadius = std::atan2(size, distance); - float integralFactor = IlluminanceIntegral(angularRadius); - float illuminance = luminance * integralFactor; - AreaLightIlluminance.SetValue(illuminance); - - float luminousPower = luminance * (4 * size * size * Pi * Pi); - AreaLightLuminousPower.SetValue(luminousPower); - - float ev100 = std::log2(luminance) + 3.0f; - AreaLightEV100.SetValue(ev100); - - if(prevUnits != currUnits) - { - AreaLightColor.SetIntensityVisible(currUnits == LightUnits::Luminance); - AreaLightIlluminance.SetVisible(currUnits == LightUnits::Illuminance); - AreaLightLuminousPower.SetVisible(currUnits == LightUnits::LuminousPower); - AreaLightEV100.SetVisible(currUnits == LightUnits::EV100); - AreaLightIlluminanceDistance.SetVisible(currUnits == LightUnits::Illuminance); - - prevUnits = currUnits; - } - } - - void UpdateUI() - { - bool enableManualExposure = ExposureMode == ExposureModes::ManualSimple; - bool enableCameraExposure = ExposureMode == ExposureModes::Manual_SBS || - ExposureMode == ExposureModes::Manual_SOS; - bool enableAutoExposure = ExposureMode == ExposureModes::Automatic; - bool enableSimpleSkyParams = SkyMode == SkyModes::Simple; - bool enableProceduralSkyParams = SkyMode == SkyModes::Procedural; - bool useHejlTM = ToneMappingMode == ToneMappingModes::Hejl2015; - bool useHableTM = ToneMappingMode == ToneMappingModes::Hable; - bool useSGSettings = SGCount() > 0; - - ManualExposure.SetEditable(enableManualExposure); - ShutterSpeed.SetEditable(enableCameraExposure); - ISORating.SetEditable(enableCameraExposure); - KeyValue.SetEditable(enableAutoExposure); - AdaptationRate.SetEditable(enableAutoExposure); - SkyColor.SetEditable(enableSimpleSkyParams); - Turbidity.SetEditable(enableProceduralSkyParams); - GroundAlbedo.SetEditable(enableProceduralSkyParams); - - WhitePoint_Hejl.SetVisible(useHejlTM); - - WhitePoint_Hable.SetVisible(useHableTM); - ShoulderStrength.SetVisible(useHableTM); - LinearStrength.SetVisible(useHableTM); - LinearAngle.SetVisible(useHableTM); - ToeStrength.SetVisible(useHableTM); - - bool enableSunDirection = SunDirType == SunDirectionTypes::UnitVector; - bool enableHorizCoord = SunDirType == SunDirectionTypes::HorizontalCoordSystem; - - SunDirection.SetVisible(enableSunDirection); - SunAzimuth.SetVisible(enableHorizCoord); - SunElevation.SetVisible(enableHorizCoord); - - SGDiffuseMode.SetEditable(useSGSettings); - SolveMode.SetEditable(useSGSettings); - - if(AppSettings::HasSunDirChanged()) - { - if(SunDirType == SunDirectionTypes::UnitVector) - { - UpdateHorizontalCoords(); - } - else if(SunDirType == SunDirectionTypes::HorizontalCoordSystem) - { - UpdateUnitVector(); - } - } - - UpdateAreaLightUnits(); - } +#include +#include +#include "AppSettings.h" + +using namespace SampleFramework11; + +static const char* SunDirectionTypesLabels[2] = +{ + "Unit Vector", + "Horizontal Coordinate System", +}; + +static const char* SkyModesLabels[6] = +{ + "None", + "Procedural", + "Simple", + "Ennis", + "Grace Cathedral", + "Uffizi Cross", +}; + +static const char* LightUnitsLabels[4] = +{ + "Luminance", + "Illuminance", + "LuminousPower", + "EV100", +}; + +static const char* ExposureModesLabels[4] = +{ + "Manual (Simple)", + "Manual (SBS)", + "Manual (SOS)", + "Automatic", +}; + +static const char* FStopsLabels[23] = +{ + "f/1.8", + "f/2.0", + "f/2.2", + "f/2.5", + "f/2.8", + "f/3.2", + "f/3.5", + "f/4.0", + "f/4.5", + "f/5.0", + "f/5.6", + "f/6.3", + "f/7.1", + "f/8.0", + "f/9.0", + "f/10.0", + "f/11.0", + "f/13.0", + "f/14.0", + "f/16.0", + "f/18.0", + "f/20.0", + "f/22.0", +}; + +static const char* ISORatingsLabels[4] = +{ + "ISO100", + "ISO200", + "ISO400", + "ISO800", +}; + +static const char* ShutterSpeedsLabels[13] = +{ + "1s", + "1/2s", + "1/4s", + "1/8s", + "1/15s", + "1/30s", + "1/60s", + "1/125s", + "1/250s", + "1/500s", + "1/1000s", + "1/2000s", + "1/4000s", +}; + +static const char* ToneMappingModesLabels[5] = +{ + "Film Stock", + "Linear", + "ACES sRGB Monitor", + "Hejl 2015", + "Hable (Uncharted2)", +}; + +static const char* MSAAModesLabels[4] = +{ + "None", + "2x", + "4x", + "8x", +}; + +static const char* FilterTypesLabels[6] = +{ + "Box", + "Triangle", + "Gaussian", + "BlackmanHarris", + "Smoothstep", + "BSpline", +}; + +static const char* JitterModesLabels[5] = +{ + "None", + "Uniform2x", + "Hammersley4x", + "Hammersley8x", + "Hammersley16x", +}; + +static const char* SGDiffuseModesLabels[3] = +{ + "InnerProduct", + "Punctual", + "Fitted (Hill 16)", +}; + +static const char* SampleModesLabels[5] = +{ + "Random", + "Stratified", + "Hammersley", + "UniformGrid", + "CMJ", +}; + +static const char* BakeModesLabels[10] = +{ + "Diffuse", + "Half-Life 2", + "L1 SH", + "L2 SH", + "L1 H-basis", + "L2 H-basis", + "SG5", + "SG6", + "SG9", + "SG12", +}; + +static const char* SolveModesLabels[3] = +{ + "Ad-Hoc Projection", + "Least Squares", + "Non-Negative Least Squares", +}; + +static const char* ProbeModesLabels[4] = +{ + "CubeMap", + "AmbientCube", + "L1 SH", + "L2 SH", +}; + +static const char* ScenesLabels[3] = +{ + "Box", + "White Room", + "Sponza", +}; + +static const char* VoxelVisualizerModesLabels[3] = +{ + "None", + "Geometry", + "RayMarch", +}; + +namespace AppSettings +{ + BoolSetting EnableSun; + BoolSetting SunAreaLightApproximation; + ColorSetting SunTintColor; + FloatSetting SunIntensityScale; + FloatSetting SunSize; + BoolSetting NormalizeSunIntensity; + SunDirectionTypesSetting SunDirType; + DirectionSetting SunDirection; + FloatSetting SunAzimuth; + FloatSetting SunElevation; + SkyModesSetting SkyMode; + ColorSetting SkyColor; + FloatSetting Turbidity; + ColorSetting GroundAlbedo; + BoolSetting EnableAreaLight; + ColorSetting AreaLightColor; + FloatSetting AreaLightIlluminance; + FloatSetting AreaLightLuminousPower; + FloatSetting AreaLightEV100; + LightUnitsSetting AreaLightUnits; + FloatSetting AreaLightIlluminanceDistance; + FloatSetting AreaLightSize; + FloatSetting AreaLightX; + FloatSetting AreaLightY; + FloatSetting AreaLightZ; + FloatSetting AreaLightShadowBias; + BoolSetting BakeDirectAreaLight; + BoolSetting EnableAreaLightShadows; + ExposureModesSetting ExposureMode; + FloatSetting ManualExposure; + FStopsSetting ApertureSize; + ISORatingsSetting ISORating; + ShutterSpeedsSetting ShutterSpeed; + FloatSetting FilmSize; + FloatSetting FocalLength; + FloatSetting FocusDistance; + IntSetting NumBlades; + BoolSetting EnableDOF; + FloatSetting KeyValue; + FloatSetting AdaptationRate; + FloatSetting ApertureFNumber; + FloatSetting ApertureWidth; + FloatSetting ShutterSpeedValue; + FloatSetting ISO; + FloatSetting BokehPolygonAmount; + ToneMappingModesSetting ToneMappingMode; + FloatSetting WhitePoint_Hejl; + FloatSetting ShoulderStrength; + FloatSetting LinearStrength; + FloatSetting LinearAngle; + FloatSetting ToeStrength; + FloatSetting WhitePoint_Hable; + MSAAModesSetting MSAAMode; + FilterTypesSetting FilterType; + FloatSetting FilterSize; + FloatSetting GaussianSigma; + BoolSetting EnableTemporalAA; + JitterModesSetting JitterMode; + FloatSetting JitterScale; + SGDiffuseModesSetting SGDiffuseMode; + BoolSetting UseASGWarp; + IntSetting LightMapResolution; + IntSetting NumBakeSamples; + SampleModesSetting BakeSampleMode; + IntSetting MaxBakePathLength; + IntSetting BakeRussianRouletteDepth; + FloatSetting BakeRussianRouletteProbability; + BakeModesSetting BakeMode; + SolveModesSetting SolveMode; + BoolSetting UseProbes; + ProbeModesSetting ProbeMode; + IntSetting ProbeResX; + IntSetting ProbeResY; + IntSetting ProbeResZ; + IntSetting ProbeCubemapCaptureRes; + IntSetting ProbeIrradianceCubemapRes; + IntSetting ProbeDistanceCubemapRes; + FloatSetting SceneBoundsScale; + BoolSetting WeightProbesByNormal; + BoolSetting WeightProbesByVisibility; + FloatSetting DistanceFilterSharpness; + IntSetting ProbeIntegrationSamples; + IntSetting ProbeDistanceIntegrationSamples; + BoolSetting BakeWithVCT; + IntSetting VoxelResolution; + ScenesSetting CurrentScene; + BoolSetting EnableDiffuse; + BoolSetting EnableSpecular; + BoolSetting EnableDirectLighting; + BoolSetting EnableIndirectLighting; + BoolSetting EnableIndirectDiffuse; + BoolSetting EnableIndirectSpecular; + BoolSetting EnableAlbedoMaps; + BoolSetting EnableNormalMaps; + FloatSetting NormalMapIntensity; + FloatSetting DiffuseAlbedoScale; + FloatSetting RoughnessScale; + BoolSetting ShowGroundTruth; + IntSetting NumRenderSamples; + SampleModesSetting RenderSampleMode; + IntSetting MaxRenderPathLength; + IntSetting RenderRussianRouletteDepth; + FloatSetting RenderRussianRouletteProbability; + BoolSetting EnableRenderBounceSpecular; + FloatSetting BloomExposure; + FloatSetting BloomMagnitude; + FloatSetting BloomBlurSigma; + BoolSetting EnableLuminancePicker; + BoolSetting ShowBakeDataVisualizer; + BoolSetting ShowProbeVisualizer; + BoolSetting ViewIndirectDiffuse; + BoolSetting ViewIndirectSpecular; + VoxelVisualizerModesSetting VoxelVisualizerMode; + IntSetting VoxelVisualizerMipLevel; + Button SaveLightSettings; + Button LoadLightSettings; + Button SaveEXRScreenshot; + BoolSetting ShowSunIntensity; + BoolSetting AlwaysRegenerateProbes; + BoolSetting AlwaysRevoxelize; + FloatSetting SceneBoundsOffsetX; + FloatSetting SceneBoundsOffsetY; + FloatSetting SceneBoundsOffsetZ; + + ConstantBuffer CBuffer; + + void Initialize(ID3D11Device* device) + { + TwBar* tweakBar = Settings.TweakBar(); + + EnableSun.Initialize(tweakBar, "EnableSun", "Sun Light", "Enable Sun", "Enables the sun light", true); + Settings.AddSetting(&EnableSun); + + SunAreaLightApproximation.Initialize(tweakBar, "SunAreaLightApproximation", "Sun Light", "Sun Area Light Approximation", "Controls whether the sun is treated as a disc area light in the real-time shader", true); + Settings.AddSetting(&SunAreaLightApproximation); + + SunTintColor.Initialize(tweakBar, "SunTintColor", "Sun Light", "Sun Tint Color", "The color of the sun", Float3(1.0000f, 1.0000f, 1.0000f), false, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ColorUnit::None); + Settings.AddSetting(&SunTintColor); + + SunIntensityScale.Initialize(tweakBar, "SunIntensityScale", "Sun Light", "Sun Intensity Scale", "Scale the intensity of the sun", 1.0000f, 0.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&SunIntensityScale); + + SunSize.Initialize(tweakBar, "SunSize", "Sun Light", "Sun Size", "Angular radius of the sun in degrees", 0.2700f, 0.0100f, 340282300000000000000000000000000000000.0000f, 0.0010f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&SunSize); + + NormalizeSunIntensity.Initialize(tweakBar, "NormalizeSunIntensity", "Sun Light", "Normalize Sun Intensity", "", false); + Settings.AddSetting(&NormalizeSunIntensity); + + SunDirType.Initialize(tweakBar, "SunDirType", "Sun Light", "Sun Dir Type", "Input direction type for the sun", SunDirectionTypes::HorizontalCoordSystem, 2, SunDirectionTypesLabels); + Settings.AddSetting(&SunDirType); + + SunDirection.Initialize(tweakBar, "SunDirection", "Sun Light", "Sun Direction", "Director of the sun", Float3(-0.7500f, 0.9770f, -0.4000f)); + Settings.AddSetting(&SunDirection); + + SunAzimuth.Initialize(tweakBar, "SunAzimuth", "Sun Light", "Sun Azimuth", "Angle around the horizon", 0.0000f, 0.0000f, 360.0000f, 0.1000f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&SunAzimuth); + + SunElevation.Initialize(tweakBar, "SunElevation", "Sun Light", "Sun Elevation", "Elevation of sun from ground. 0 degrees is aligned on the horizon while 90 degrees is directly overhead", 0.0000f, 0.0000f, 90.0000f, 0.1000f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&SunElevation); + + SkyMode.Initialize(tweakBar, "SkyMode", "Sky", "Sky Mode", "Controls the sky used for GI baking and background rendering", SkyModes::Procedural, 6, SkyModesLabels); + Settings.AddSetting(&SkyMode); + + SkyColor.Initialize(tweakBar, "SkyColor", "Sky", "Sky Color", "The color of the simple sky", Float3(1400.0000f, 3500.0000f, 7000.0000f), true, 0.0000f, 1000000.0000f, 0.1000f, ColorUnit::Luminance); + Settings.AddSetting(&SkyColor); + + Turbidity.Initialize(tweakBar, "Turbidity", "Sky", "Turbidity", "", 2.0000f, 1.0000f, 10.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&Turbidity); + + GroundAlbedo.Initialize(tweakBar, "GroundAlbedo", "Sky", "Ground Albedo", "", Float3(0.5000f, 0.5000f, 0.5000f), false, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ColorUnit::None); + Settings.AddSetting(&GroundAlbedo); + + EnableAreaLight.Initialize(tweakBar, "EnableAreaLight", "Area Light", "Enable Area Light", "Enables the area light during baking and ground truth rendering", false); + Settings.AddSetting(&EnableAreaLight); + + AreaLightColor.Initialize(tweakBar, "AreaLightColor", "Area Light", "Color", "The color of the area light", Float3(1000000.0000f, 1000000.0000f, 1000000.0000f), true, 0.0000f, 340282300000000000000000000000000000000.0000f, 0.1000f, ColorUnit::Luminance); + Settings.AddSetting(&AreaLightColor); + + AreaLightIlluminance.Initialize(tweakBar, "AreaLightIlluminance", "Area Light", "Color Intensity (lux)", "", 1.0000f, 0.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&AreaLightIlluminance); + AreaLightIlluminance.SetVisible(false); + + AreaLightLuminousPower.Initialize(tweakBar, "AreaLightLuminousPower", "Area Light", "Color Intensity (lm)", "", 1.0000f, 0.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&AreaLightLuminousPower); + AreaLightLuminousPower.SetVisible(false); + + AreaLightEV100.Initialize(tweakBar, "AreaLightEV100", "Area Light", "Color Intensity (EV100)", "", 0.0000f, -64.0000f, 64.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&AreaLightEV100); + AreaLightEV100.SetVisible(false); + + AreaLightUnits.Initialize(tweakBar, "AreaLightUnits", "Area Light", "Units", "", LightUnits::Luminance, 4, LightUnitsLabels); + Settings.AddSetting(&AreaLightUnits); + + AreaLightIlluminanceDistance.Initialize(tweakBar, "AreaLightIlluminanceDistance", "Area Light", "Illuminance Distance", "", 10.0000f, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&AreaLightIlluminanceDistance); + AreaLightIlluminanceDistance.SetVisible(false); + + AreaLightSize.Initialize(tweakBar, "AreaLightSize", "Area Light", "Size", "The radius of the area light", 0.5000f, 0.0100f, 10.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&AreaLightSize); + + AreaLightX.Initialize(tweakBar, "AreaLightX", "Area Light", "Position X", "The X coordinate of the area light", 0.0000f, -100.0000f, 100.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&AreaLightX); + + AreaLightY.Initialize(tweakBar, "AreaLightY", "Area Light", "Position Y", "The Y coordinate of the area light", 5.0000f, -100.0000f, 100.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&AreaLightY); + + AreaLightZ.Initialize(tweakBar, "AreaLightZ", "Area Light", "Position Z", "The Z coordinate of the area light", 0.0000f, -100.0000f, 100.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&AreaLightZ); + + AreaLightShadowBias.Initialize(tweakBar, "AreaLightShadowBias", "Area Light", "Shadow Bias", "", 0.0010f, 0.0000f, 1.0000f, 0.0010f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&AreaLightShadowBias); + + BakeDirectAreaLight.Initialize(tweakBar, "BakeDirectAreaLight", "Area Light", "Bake Direct Area Light", "Bakes the direct contribution from the area light into the light map", false); + Settings.AddSetting(&BakeDirectAreaLight); + + EnableAreaLightShadows.Initialize(tweakBar, "EnableAreaLightShadows", "Area Light", "Enable Area Light Shadows", "", true); + Settings.AddSetting(&EnableAreaLightShadows); + + ExposureMode.Initialize(tweakBar, "ExposureMode", "Camera Controls", "Exposure Mode", "Specifies how exposure should be controled", ExposureModes::Manual_SBS, 4, ExposureModesLabels); + Settings.AddSetting(&ExposureMode); + + ManualExposure.Initialize(tweakBar, "ManualExposure", "Camera Controls", "Manual Exposure", "Manual exposure value when auto-exposure is disabled", -16.0000f, -32.0000f, 32.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&ManualExposure); + + ApertureSize.Initialize(tweakBar, "ApertureSize", "Camera Controls", "Aperture", "", FStops::FStop16Point0, 23, FStopsLabels); + Settings.AddSetting(&ApertureSize); + + ISORating.Initialize(tweakBar, "ISORating", "Camera Controls", "ISO Rating", "", ISORatings::ISO100, 4, ISORatingsLabels); + Settings.AddSetting(&ISORating); + + ShutterSpeed.Initialize(tweakBar, "ShutterSpeed", "Camera Controls", "Shutter Speed", "", ShutterSpeeds::ShutterSpeed1Over125, 13, ShutterSpeedsLabels); + Settings.AddSetting(&ShutterSpeed); + + FilmSize.Initialize(tweakBar, "FilmSize", "Camera Controls", "Film Size(mm)", "", 35.0000f, 1.0000f, 100.0000f, 0.1000f, ConversionMode::None, 0.0010f); + Settings.AddSetting(&FilmSize); + + FocalLength.Initialize(tweakBar, "FocalLength", "Camera Controls", "Focal Length(mm)", "", 35.0000f, 1.0000f, 200.0000f, 0.1000f, ConversionMode::None, 0.0010f); + Settings.AddSetting(&FocalLength); + + FocusDistance.Initialize(tweakBar, "FocusDistance", "Camera Controls", "Focus Distance", "", 10.0000f, 1.0000f, 100.0000f, 0.1000f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&FocusDistance); + + NumBlades.Initialize(tweakBar, "NumBlades", "Camera Controls", "Num Aperture Blades", "", 5, 5, 9); + Settings.AddSetting(&NumBlades); + + EnableDOF.Initialize(tweakBar, "EnableDOF", "Camera Controls", "Enable DOF", "", false); + Settings.AddSetting(&EnableDOF); + + KeyValue.Initialize(tweakBar, "KeyValue", "Camera Controls", "Auto-Exposure Key Value", "Parameter that biases the result of the auto-exposure pass", 0.1150f, 0.0000f, 0.5000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&KeyValue); + + AdaptationRate.Initialize(tweakBar, "AdaptationRate", "Camera Controls", "Adaptation Rate", "Controls how quickly auto-exposure adapts to changes in scene brightness", 0.5000f, 0.0000f, 4.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&AdaptationRate); + + ApertureFNumber.Initialize(tweakBar, "ApertureFNumber", "Camera Controls", "Aperture FNumber", "", 0.0000f, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&ApertureFNumber); + ApertureFNumber.SetVisible(false); + ApertureFNumber.SetEditable(false); + + ApertureWidth.Initialize(tweakBar, "ApertureWidth", "Camera Controls", "Aperture Width", "", 0.0000f, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&ApertureWidth); + ApertureWidth.SetVisible(false); + ApertureWidth.SetEditable(false); + + ShutterSpeedValue.Initialize(tweakBar, "ShutterSpeedValue", "Camera Controls", "Shutter Speed Value", "", 0.0000f, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&ShutterSpeedValue); + ShutterSpeedValue.SetVisible(false); + ShutterSpeedValue.SetEditable(false); + + ISO.Initialize(tweakBar, "ISO", "Camera Controls", "ISO", "", 0.0000f, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&ISO); + ISO.SetVisible(false); + ISO.SetEditable(false); + + BokehPolygonAmount.Initialize(tweakBar, "BokehPolygonAmount", "Camera Controls", "Bokeh Polygon Amount", "", 0.0000f, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&BokehPolygonAmount); + BokehPolygonAmount.SetVisible(false); + BokehPolygonAmount.SetEditable(false); + + ToneMappingMode.Initialize(tweakBar, "ToneMappingMode", "Tone Mapping", "Tone Mapping Operator", "", ToneMappingModes::ACES, 5, ToneMappingModesLabels); + Settings.AddSetting(&ToneMappingMode); + + WhitePoint_Hejl.Initialize(tweakBar, "WhitePoint_Hejl", "Tone Mapping", "White Point (Hejl2015)", "", 1.0000f, 0.0100f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&WhitePoint_Hejl); + + ShoulderStrength.Initialize(tweakBar, "ShoulderStrength", "Tone Mapping", "Shoulder Strength", "", 4.0000f, 0.0100f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&ShoulderStrength); + + LinearStrength.Initialize(tweakBar, "LinearStrength", "Tone Mapping", "Linear Strength", "", 5.0000f, 0.0100f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&LinearStrength); + + LinearAngle.Initialize(tweakBar, "LinearAngle", "Tone Mapping", "Linear Angle", "", 0.1200f, 0.0100f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&LinearAngle); + + ToeStrength.Initialize(tweakBar, "ToeStrength", "Tone Mapping", "Toe Strength", "", 13.0000f, 0.0100f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&ToeStrength); + + WhitePoint_Hable.Initialize(tweakBar, "WhitePoint_Hable", "Tone Mapping", "White Point (Hable)", "", 6.0000f, 0.0100f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&WhitePoint_Hable); + + MSAAMode.Initialize(tweakBar, "MSAAMode", "Anti Aliasing", "MSAAMode", "", MSAAModes::MSAA4x, 4, MSAAModesLabels); + Settings.AddSetting(&MSAAMode); + + FilterType.Initialize(tweakBar, "FilterType", "Anti Aliasing", "Filter Type", "", FilterTypes::Smoothstep, 6, FilterTypesLabels); + Settings.AddSetting(&FilterType); + + FilterSize.Initialize(tweakBar, "FilterSize", "Anti Aliasing", "Filter Size", "", 2.0000f, 0.0000f, 6.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&FilterSize); + + GaussianSigma.Initialize(tweakBar, "GaussianSigma", "Anti Aliasing", "Gaussian Sigma", "", 0.5000f, 0.0100f, 1.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&GaussianSigma); + + EnableTemporalAA.Initialize(tweakBar, "EnableTemporalAA", "Anti Aliasing", "Enable Temporal AA", "", true); + Settings.AddSetting(&EnableTemporalAA); + + JitterMode.Initialize(tweakBar, "JitterMode", "Anti Aliasing", "Jitter Mode", "", JitterModes::Hammersley4x, 5, JitterModesLabels); + Settings.AddSetting(&JitterMode); + + JitterScale.Initialize(tweakBar, "JitterScale", "Anti Aliasing", "Jitter Scale", "", 1.0000f, 0.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&JitterScale); + + SGDiffuseMode.Initialize(tweakBar, "SGDiffuseMode", "SG Settings", "SG Diffuse Mode", "", SGDiffuseModes::Fitted, 3, SGDiffuseModesLabels); + Settings.AddSetting(&SGDiffuseMode); + + UseASGWarp.Initialize(tweakBar, "UseASGWarp", "SG Settings", "Use ASG Warp", "", true); + Settings.AddSetting(&UseASGWarp); + + LightMapResolution.Initialize(tweakBar, "LightMapResolution", "Baking", "Light Map Resolution", "The texture resolution of the light map", 256, 64, 4096); + Settings.AddSetting(&LightMapResolution); + + NumBakeSamples.Initialize(tweakBar, "NumBakeSamples", "Baking", "Sqrt Num Samples", "The square root of the number of sample rays to use for baking GI", 25, 1, 100); + Settings.AddSetting(&NumBakeSamples); + + BakeSampleMode.Initialize(tweakBar, "BakeSampleMode", "Baking", "Sample Mode", "", SampleModes::CMJ, 5, SampleModesLabels); + Settings.AddSetting(&BakeSampleMode); + + MaxBakePathLength.Initialize(tweakBar, "MaxBakePathLength", "Baking", "Max Bake Path Length", "Maximum path length (bounces + 2) to use for baking GI (set to -1 for infinite)", -1, -1, 2147483647); + Settings.AddSetting(&MaxBakePathLength); + + BakeRussianRouletteDepth.Initialize(tweakBar, "BakeRussianRouletteDepth", "Baking", "Russian Roullette Depth", "Path length at which Russian roulette kicks in (-1 to disable)", 4, -1, 2147483647); + Settings.AddSetting(&BakeRussianRouletteDepth); + + BakeRussianRouletteProbability.Initialize(tweakBar, "BakeRussianRouletteProbability", "Baking", "Russian Roullette Probability", "Maximum probability for continuing when Russian roulette is used", 0.5000f, 0.0000f, 1.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&BakeRussianRouletteProbability); + + BakeMode.Initialize(tweakBar, "BakeMode", "Baking", "Bake Mode", "", BakeModes::H4, 10, BakeModesLabels); + Settings.AddSetting(&BakeMode); + + SolveMode.Initialize(tweakBar, "SolveMode", "Baking", "Solve Mode", "", SolveModes::NNLS, 3, SolveModesLabels); + Settings.AddSetting(&SolveMode); + + UseProbes.Initialize(tweakBar, "UseProbes", "Probes", "Use Probes", "", true); + Settings.AddSetting(&UseProbes); + + ProbeMode.Initialize(tweakBar, "ProbeMode", "Probes", "Probe Mode", "", ProbeModes::CubeMap, 4, ProbeModesLabels); + Settings.AddSetting(&ProbeMode); + + ProbeResX.Initialize(tweakBar, "ProbeResX", "Probes", "Probe Res X", "", 4, 1, 2048); + Settings.AddSetting(&ProbeResX); + + ProbeResY.Initialize(tweakBar, "ProbeResY", "Probes", "Probe Res Y", "", 4, 1, 2048); + Settings.AddSetting(&ProbeResY); + + ProbeResZ.Initialize(tweakBar, "ProbeResZ", "Probes", "Probe Res Z", "", 4, 1, 2048); + Settings.AddSetting(&ProbeResZ); + + ProbeCubemapCaptureRes.Initialize(tweakBar, "ProbeCubemapCaptureRes", "Probes", "Probe Cubemap Capture Res", "", 256, 1, 4096); + Settings.AddSetting(&ProbeCubemapCaptureRes); + + ProbeIrradianceCubemapRes.Initialize(tweakBar, "ProbeIrradianceCubemapRes", "Probes", "Probe Irradiance Cubemap Res", "", 16, 1, 4096); + Settings.AddSetting(&ProbeIrradianceCubemapRes); + + ProbeDistanceCubemapRes.Initialize(tweakBar, "ProbeDistanceCubemapRes", "Probes", "Probe Distance Cubemap Res", "", 128, 1, 4096); + Settings.AddSetting(&ProbeDistanceCubemapRes); + + SceneBoundsScale.Initialize(tweakBar, "SceneBoundsScale", "Probes", "Scene Bounds Scale", "", 1.4500f, -340282300000000000000000000000000000000.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&SceneBoundsScale); + + WeightProbesByNormal.Initialize(tweakBar, "WeightProbesByNormal", "Probes", "Weight Probes By Normal", "", true); + Settings.AddSetting(&WeightProbesByNormal); + + WeightProbesByVisibility.Initialize(tweakBar, "WeightProbesByVisibility", "Probes", "Weight Probes By Visibility", "", true); + Settings.AddSetting(&WeightProbesByVisibility); + + DistanceFilterSharpness.Initialize(tweakBar, "DistanceFilterSharpness", "Probes", "Distance Filter Sharpness", "", 10.0000f, 1.0000f, 20.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&DistanceFilterSharpness); + + ProbeIntegrationSamples.Initialize(tweakBar, "ProbeIntegrationSamples", "Probes", "Probe Integration Samples", "", 32, 1, 64); + Settings.AddSetting(&ProbeIntegrationSamples); + + ProbeDistanceIntegrationSamples.Initialize(tweakBar, "ProbeDistanceIntegrationSamples", "Probes", "Probe Distance Integration Samples", "", 32, 1, 64); + Settings.AddSetting(&ProbeDistanceIntegrationSamples); + + BakeWithVCT.Initialize(tweakBar, "BakeWithVCT", "VCT", "Bake With VCT", "", false); + Settings.AddSetting(&BakeWithVCT); + + VoxelResolution.Initialize(tweakBar, "VoxelResolution", "VCT", "Voxel Resolution", "", 64, 2, 2048); + Settings.AddSetting(&VoxelResolution); + + CurrentScene.Initialize(tweakBar, "CurrentScene", "Scene", "Current Scene", "", Scenes::Box, 3, ScenesLabels); + Settings.AddSetting(&CurrentScene); + + EnableDiffuse.Initialize(tweakBar, "EnableDiffuse", "Scene", "Enable Diffuse", "Enables diffuse lighting", true); + Settings.AddSetting(&EnableDiffuse); + + EnableSpecular.Initialize(tweakBar, "EnableSpecular", "Scene", "Enable Specular", "Enables specular lighting", true); + Settings.AddSetting(&EnableSpecular); + + EnableDirectLighting.Initialize(tweakBar, "EnableDirectLighting", "Scene", "Enable Direct Lighting", "Enables direct lighting", true); + Settings.AddSetting(&EnableDirectLighting); + + EnableIndirectLighting.Initialize(tweakBar, "EnableIndirectLighting", "Scene", "Enable Indirect Lighting", "Enables indirect lighting", true); + Settings.AddSetting(&EnableIndirectLighting); + + EnableIndirectDiffuse.Initialize(tweakBar, "EnableIndirectDiffuse", "Scene", "Enable Indirect Diffuse", "Enables indirect diffuse lighting", true); + Settings.AddSetting(&EnableIndirectDiffuse); + + EnableIndirectSpecular.Initialize(tweakBar, "EnableIndirectSpecular", "Scene", "Enable Indirect Specular", "Enables indirect specular lighting", false); + Settings.AddSetting(&EnableIndirectSpecular); + + EnableAlbedoMaps.Initialize(tweakBar, "EnableAlbedoMaps", "Scene", "Enable Albedo Maps", "Enables albedo maps", true); + Settings.AddSetting(&EnableAlbedoMaps); + + EnableNormalMaps.Initialize(tweakBar, "EnableNormalMaps", "Scene", "Enable Normal Maps", "Enables normal maps", true); + Settings.AddSetting(&EnableNormalMaps); + + NormalMapIntensity.Initialize(tweakBar, "NormalMapIntensity", "Scene", "Normal Map Intensity", "Intensity of the normal map", 0.5000f, 0.0000f, 1.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&NormalMapIntensity); + + DiffuseAlbedoScale.Initialize(tweakBar, "DiffuseAlbedoScale", "Scene", "Diffuse Albedo Scale", "Global scale applied to all material diffuse albedo values", 0.5000f, 0.0000f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&DiffuseAlbedoScale); + + RoughnessScale.Initialize(tweakBar, "RoughnessScale", "Scene", "Specular Roughness Scale", "Global scale applied to all material roughness values", 2.0000f, 0.0100f, 340282300000000000000000000000000000000.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&RoughnessScale); + + ShowGroundTruth.Initialize(tweakBar, "ShowGroundTruth", "Ground Truth", "Show Ground Truth", "If enabled, shows a ground truth image rendered on the CPU", false); + Settings.AddSetting(&ShowGroundTruth); + + NumRenderSamples.Initialize(tweakBar, "NumRenderSamples", "Ground Truth", "Sqrt Num Samples", "The square root of the number of per-pixel sample rays to use for ground truth rendering", 4, 1, 100); + Settings.AddSetting(&NumRenderSamples); + + RenderSampleMode.Initialize(tweakBar, "RenderSampleMode", "Ground Truth", "Sample Mode", "", SampleModes::CMJ, 5, SampleModesLabels); + Settings.AddSetting(&RenderSampleMode); + + MaxRenderPathLength.Initialize(tweakBar, "MaxRenderPathLength", "Ground Truth", "Max Path Length", "Maximum path length (bounces) to use for ground truth rendering (set to -1 for infinite)", -1, -1, 2147483647); + Settings.AddSetting(&MaxRenderPathLength); + + RenderRussianRouletteDepth.Initialize(tweakBar, "RenderRussianRouletteDepth", "Ground Truth", "Russian Roullette Depth", "Path length at which Russian roulette kicks in (-1 to disable)", 4, -1, 2147483647); + Settings.AddSetting(&RenderRussianRouletteDepth); + + RenderRussianRouletteProbability.Initialize(tweakBar, "RenderRussianRouletteProbability", "Ground Truth", "Russian Roullette Probability", "Maximum probability for continuing when Russian roulette is used", 0.5000f, 0.0000f, 1.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&RenderRussianRouletteProbability); + + EnableRenderBounceSpecular.Initialize(tweakBar, "EnableRenderBounceSpecular", "Ground Truth", "Enable Bounce Specular", "Enables specular calculations after the first hit", false); + Settings.AddSetting(&EnableRenderBounceSpecular); + + BloomExposure.Initialize(tweakBar, "BloomExposure", "Post Processing", "Bloom Exposure Offset", "Exposure offset applied to generate the input of the bloom pass", -4.0000f, -10.0000f, 0.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&BloomExposure); + + BloomMagnitude.Initialize(tweakBar, "BloomMagnitude", "Post Processing", "Bloom Magnitude", "Scale factor applied to the bloom results when combined with tone-mapped result", 1.0000f, 0.0000f, 2.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&BloomMagnitude); + + BloomBlurSigma.Initialize(tweakBar, "BloomBlurSigma", "Post Processing", "Bloom Blur Sigma", "Sigma parameter of the Gaussian filter used in the bloom pass", 2.5000f, 0.5000f, 2.5000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&BloomBlurSigma); + + EnableLuminancePicker.Initialize(tweakBar, "EnableLuminancePicker", "Debug", "Enable Luminance Picker", "", false); + Settings.AddSetting(&EnableLuminancePicker); + + ShowBakeDataVisualizer.Initialize(tweakBar, "ShowBakeDataVisualizer", "Debug", "Show Bake Data Visualizer", "", false); + Settings.AddSetting(&ShowBakeDataVisualizer); + + ShowProbeVisualizer.Initialize(tweakBar, "ShowProbeVisualizer", "Debug", "Show Probe Visualizer", "", false); + Settings.AddSetting(&ShowProbeVisualizer); + + ViewIndirectDiffuse.Initialize(tweakBar, "ViewIndirectDiffuse", "Debug", "View Indirect Diffuse", "", false); + Settings.AddSetting(&ViewIndirectDiffuse); + + ViewIndirectSpecular.Initialize(tweakBar, "ViewIndirectSpecular", "Debug", "View Indirect Specular", "", false); + Settings.AddSetting(&ViewIndirectSpecular); + + VoxelVisualizerMode.Initialize(tweakBar, "VoxelVisualizerMode", "Debug", "Voxel Visualizer Mode", "", VoxelVisualizerModes::None, 3, VoxelVisualizerModesLabels); + Settings.AddSetting(&VoxelVisualizerMode); + + VoxelVisualizerMipLevel.Initialize(tweakBar, "VoxelVisualizerMipLevel", "Debug", "Voxel Visualizer Mip Level", "", 0, 0, 16); + Settings.AddSetting(&VoxelVisualizerMipLevel); + + SaveLightSettings.Initialize(tweakBar, "SaveLightSettings", "Debug", "Save Light Settings", "Saves the lighting settings to a file"); + Settings.AddSetting(&SaveLightSettings); + + LoadLightSettings.Initialize(tweakBar, "LoadLightSettings", "Debug", "Load Light Settings", "Loads the lighting settings from a file"); + Settings.AddSetting(&LoadLightSettings); + + SaveEXRScreenshot.Initialize(tweakBar, "SaveEXRScreenshot", "Debug", "Save EXR Screenshot", "Captures the current screen image in EXR format"); + Settings.AddSetting(&SaveEXRScreenshot); + + ShowSunIntensity.Initialize(tweakBar, "ShowSunIntensity", "Debug", "Show Sun Intensity", "", false); + Settings.AddSetting(&ShowSunIntensity); + + AlwaysRegenerateProbes.Initialize(tweakBar, "AlwaysRegenerateProbes", "Debug", "Always Regenerate Probes", "", false); + Settings.AddSetting(&AlwaysRegenerateProbes); + + AlwaysRevoxelize.Initialize(tweakBar, "AlwaysRevoxelize", "Debug", "Always Revoxelize", "", false); + Settings.AddSetting(&AlwaysRevoxelize); + + SceneBoundsOffsetX.Initialize(tweakBar, "SceneBoundsOffsetX", "Debug", "Scene Bounds Offset X", "", 0.0000f, -100.0000f, 100.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&SceneBoundsOffsetX); + + SceneBoundsOffsetY.Initialize(tweakBar, "SceneBoundsOffsetY", "Debug", "Scene Bounds Offset Y", "", 0.0000f, -100.0000f, 100.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&SceneBoundsOffsetY); + + SceneBoundsOffsetZ.Initialize(tweakBar, "SceneBoundsOffsetZ", "Debug", "Scene Bounds Offset Z", "", 0.0000f, -100.0000f, 100.0000f, 0.0100f, ConversionMode::None, 1.0000f); + Settings.AddSetting(&SceneBoundsOffsetZ); + + TwHelper::SetOpened(tweakBar, "Sun Light", true); + + TwHelper::SetOpened(tweakBar, "Sky", true); + + TwHelper::SetOpened(tweakBar, "Area Light", false); + + TwHelper::SetOpened(tweakBar, "Camera Controls", false); + + TwHelper::SetOpened(tweakBar, "Tone Mapping", false); + + TwHelper::SetOpened(tweakBar, "Anti Aliasing", false); + + TwHelper::SetOpened(tweakBar, "SG Settings", false); + + TwHelper::SetOpened(tweakBar, "Baking", false); + + TwHelper::SetOpened(tweakBar, "Probes", true); + + TwHelper::SetOpened(tweakBar, "VCT", false); + + TwHelper::SetOpened(tweakBar, "Scene", false); + + TwHelper::SetOpened(tweakBar, "Ground Truth", false); + + TwHelper::SetOpened(tweakBar, "Post Processing", false); + + TwHelper::SetOpened(tweakBar, "Debug", true); + + CBuffer.Initialize(device); + } + + void Update() + { + ApertureFNumber.SetValue(ApertureFNumber_()); + ApertureWidth.SetValue(ApertureWidth_()); + ShutterSpeedValue.SetValue(ShutterSpeedValue_()); + ISO.SetValue(ISO_()); + BokehPolygonAmount.SetValue(BokehPolygonAmount_()); + } + + void UpdateCBuffer(ID3D11DeviceContext* context) + { + CBuffer.Data.EnableSun = EnableSun; + CBuffer.Data.SunAreaLightApproximation = SunAreaLightApproximation; + CBuffer.Data.SunTintColor = SunTintColor; + CBuffer.Data.SunIntensityScale = SunIntensityScale; + CBuffer.Data.SunSize = SunSize; + CBuffer.Data.SunDirType = SunDirType; + CBuffer.Data.SunDirection = SunDirection; + CBuffer.Data.SunAzimuth = SunAzimuth; + CBuffer.Data.SunElevation = SunElevation; + CBuffer.Data.EnableAreaLight = EnableAreaLight; + CBuffer.Data.AreaLightColor = AreaLightColor; + CBuffer.Data.AreaLightSize = AreaLightSize; + CBuffer.Data.AreaLightX = AreaLightX; + CBuffer.Data.AreaLightY = AreaLightY; + CBuffer.Data.AreaLightZ = AreaLightZ; + CBuffer.Data.AreaLightShadowBias = AreaLightShadowBias; + CBuffer.Data.BakeDirectAreaLight = BakeDirectAreaLight; + CBuffer.Data.EnableAreaLightShadows = EnableAreaLightShadows; + CBuffer.Data.ExposureMode = ExposureMode; + CBuffer.Data.ManualExposure = ManualExposure; + CBuffer.Data.FilmSize = FilmSize; + CBuffer.Data.FocalLength = FocalLength; + CBuffer.Data.FocusDistance = FocusDistance; + CBuffer.Data.NumBlades = NumBlades; + CBuffer.Data.KeyValue = KeyValue; + CBuffer.Data.AdaptationRate = AdaptationRate; + CBuffer.Data.ApertureFNumber = ApertureFNumber; + CBuffer.Data.ApertureWidth = ApertureWidth; + CBuffer.Data.ShutterSpeedValue = ShutterSpeedValue; + CBuffer.Data.ISO = ISO; + CBuffer.Data.BokehPolygonAmount = BokehPolygonAmount; + CBuffer.Data.ToneMappingMode = ToneMappingMode; + CBuffer.Data.WhitePoint_Hejl = WhitePoint_Hejl; + CBuffer.Data.ShoulderStrength = ShoulderStrength; + CBuffer.Data.LinearStrength = LinearStrength; + CBuffer.Data.LinearAngle = LinearAngle; + CBuffer.Data.ToeStrength = ToeStrength; + CBuffer.Data.WhitePoint_Hable = WhitePoint_Hable; + CBuffer.Data.MSAAMode = MSAAMode; + CBuffer.Data.FilterType = FilterType; + CBuffer.Data.FilterSize = FilterSize; + CBuffer.Data.GaussianSigma = GaussianSigma; + CBuffer.Data.SGDiffuseMode = SGDiffuseMode; + CBuffer.Data.UseASGWarp = UseASGWarp; + CBuffer.Data.LightMapResolution = LightMapResolution; + CBuffer.Data.BakeMode = BakeMode; + CBuffer.Data.SolveMode = SolveMode; + CBuffer.Data.UseProbes = UseProbes; + CBuffer.Data.ProbeMode = ProbeMode; + CBuffer.Data.ProbeResX = ProbeResX; + CBuffer.Data.ProbeResY = ProbeResY; + CBuffer.Data.ProbeResZ = ProbeResZ; + CBuffer.Data.ProbeCubemapCaptureRes = ProbeCubemapCaptureRes; + CBuffer.Data.ProbeIrradianceCubemapRes = ProbeIrradianceCubemapRes; + CBuffer.Data.ProbeDistanceCubemapRes = ProbeDistanceCubemapRes; + CBuffer.Data.WeightProbesByNormal = WeightProbesByNormal; + CBuffer.Data.WeightProbesByVisibility = WeightProbesByVisibility; + CBuffer.Data.DistanceFilterSharpness = DistanceFilterSharpness; + CBuffer.Data.ProbeIntegrationSamples = ProbeIntegrationSamples; + CBuffer.Data.ProbeDistanceIntegrationSamples = ProbeDistanceIntegrationSamples; + CBuffer.Data.BakeWithVCT = BakeWithVCT; + CBuffer.Data.VoxelResolution = VoxelResolution; + CBuffer.Data.EnableDiffuse = EnableDiffuse; + CBuffer.Data.EnableSpecular = EnableSpecular; + CBuffer.Data.EnableDirectLighting = EnableDirectLighting; + CBuffer.Data.EnableIndirectLighting = EnableIndirectLighting; + CBuffer.Data.EnableIndirectDiffuse = EnableIndirectDiffuse; + CBuffer.Data.EnableIndirectSpecular = EnableIndirectSpecular; + CBuffer.Data.EnableAlbedoMaps = EnableAlbedoMaps; + CBuffer.Data.EnableNormalMaps = EnableNormalMaps; + CBuffer.Data.NormalMapIntensity = NormalMapIntensity; + CBuffer.Data.DiffuseAlbedoScale = DiffuseAlbedoScale; + CBuffer.Data.RoughnessScale = RoughnessScale; + CBuffer.Data.BloomExposure = BloomExposure; + CBuffer.Data.BloomMagnitude = BloomMagnitude; + CBuffer.Data.BloomBlurSigma = BloomBlurSigma; + CBuffer.Data.ViewIndirectDiffuse = ViewIndirectDiffuse; + CBuffer.Data.ViewIndirectSpecular = ViewIndirectSpecular; + CBuffer.Data.VoxelVisualizerMipLevel = VoxelVisualizerMipLevel; + + CBuffer.ApplyChanges(context); + CBuffer.SetVS(context, 7); + CBuffer.SetHS(context, 7); + CBuffer.SetDS(context, 7); + CBuffer.SetGS(context, 7); + CBuffer.SetPS(context, 7); + CBuffer.SetCS(context, 7); + } +} + +// ================================================================================================ + +#include +#include +#include + +namespace AppSettings +{ + // Returns the result of performing a irradiance/illuminance integral over the portion + // of the hemisphere covered by a region with angular radius = theta + static float IlluminanceIntegral(float theta) + { + float cosTheta = std::cos(theta); + return Pi * (1.0f - (cosTheta * cosTheta)); + } + + Float3 SunLuminance(bool& cached) + { + Float3 sunDirection = AppSettings::SunDirection; + sunDirection.y = Saturate(sunDirection.y); + sunDirection = Float3::Normalize(sunDirection); + const float turbidity = Clamp(AppSettings::Turbidity.Value(), 1.0f, 32.0f); + const float intensityScale = AppSettings::SunIntensityScale; + const Float3 tintColor = AppSettings::SunTintColor; + const bool32 normalizeIntensity = AppSettings::NormalizeSunIntensity; + const float sunSize = AppSettings::SunSize; + + static float turbidityCache = 2.0f; + static Float3 sunDirectionCache = Float3(-0.579149902f, 0.754439294f, -0.308879942f); + static Float3 luminanceCache = Float3(1.61212531e+009f, 1.36822630e+009f, 1.07235315e+009f) * FP16Scale; + static Float3 sunTintCache = Float3(1.0f, 1.0f, 1.0f); + static float sunIntensityCache = 1.0f; + static bool32 normalizeCache = false; + static float sunSizeCache = AppSettings::BaseSunSize; + + if(turbidityCache == turbidity && sunDirection == sunDirectionCache + && intensityScale == sunIntensityCache && tintColor == sunTintCache + && normalizeCache == normalizeIntensity && sunSize == sunSizeCache) + { + cached = true; + return luminanceCache; + } + + cached = false; + + float thetaS = std::acos(1.0f - sunDirection.y); + float elevation = Pi_2 - thetaS; + + // Get the sun's luminance, then apply tint and scale factors + Float3 sunLuminance; + + // For now, we'll compute an average luminance value from Hosek solar radiance model, even though + // we could compute illuminance directly while we're sampling the disk + SampledSpectrum groundAlbedoSpectrum = SampledSpectrum::FromRGB(GroundAlbedo); + SampledSpectrum solarRadiance; + + const uint64 NumDiscSamples = 8; + for(uint64 x = 0; x < NumDiscSamples; ++x) + { + for(uint64 y = 0; y < NumDiscSamples; ++y) + { + float u = (x + 0.5f) / NumDiscSamples; + float v = (y + 0.5f) / NumDiscSamples; + Float2 discSamplePos = SquareToConcentricDiskMapping(u, v); + + float theta = elevation + discSamplePos.y * DegToRad(AppSettings::BaseSunSize); + float gamma = discSamplePos.x * DegToRad(AppSettings::BaseSunSize); + + for(int32 i = 0; i < NumSpectralSamples; ++i) + { + ArHosekSkyModelState* skyState = arhosekskymodelstate_alloc_init(elevation, turbidity, groundAlbedoSpectrum[i]); + float wavelength = Lerp(float(SampledLambdaStart), float(SampledLambdaEnd), i / float(NumSpectralSamples)); + + solarRadiance[i] = float(arhosekskymodel_solar_radiance(skyState, theta, gamma, wavelength)); + + arhosekskymodelstate_free(skyState); + skyState = nullptr; + } + + Float3 sampleRadiance = solarRadiance.ToRGB() * FP16Scale; + sunLuminance += sampleRadiance; + } + } + + // Account for luminous efficiency, coordinate system scaling, and sample averaging + sunLuminance *= 683.0f * 100.0f * (1.0f / NumDiscSamples) * (1.0f / NumDiscSamples); + + sunLuminance = sunLuminance * tintColor; + sunLuminance = sunLuminance * intensityScale; + + if(normalizeIntensity) + { + // Normalize so that the intensity stays the same even when the sun is bigger or smaller + const float baseIntegral = IlluminanceIntegral(DegToRad(AppSettings::BaseSunSize)); + const float currIntegral = IlluminanceIntegral(DegToRad(AppSettings::SunSize)); + sunLuminance *= (baseIntegral / currIntegral); + } + + turbidityCache = turbidity; + sunDirectionCache = sunDirection; + luminanceCache = sunLuminance; + sunIntensityCache = intensityScale; + sunTintCache = tintColor; + normalizeCache = normalizeIntensity; + sunSizeCache = sunSize; + + return sunLuminance; + } + + Float3 SunLuminance() + { + bool cached = false; + return SunLuminance(cached); + } + + Float3 SunIlluminance() + { + Float3 sunLuminance = SunLuminance(); + + // Compute partial integral over the hemisphere in order to compute illuminance + float theta = DegToRad(AppSettings::SunSize); + float integralFactor = IlluminanceIntegral(theta); + + return sunLuminance * integralFactor; + } + + static void UpdateAreaLightUnits() + { + static LightUnits prevUnits = AreaLightUnits; + const LightUnits currUnits = AreaLightUnits; + + const float size = AreaLightSize; + const float distance = AreaLightIlluminanceDistance; + + // Compute the luminance from our currently active unit + float luminance = AreaLightColor.Intensity(); + if(prevUnits == LightUnits::Illuminance) + { + float illuminance = AreaLightIlluminance; + float angularRadius = std::atan2(size, distance); + float integralFactor = IlluminanceIntegral(angularRadius); + luminance = illuminance / integralFactor; + } + else if(prevUnits == LightUnits::LuminousPower) + { + float luminousPower = AreaLightLuminousPower; + luminance = luminousPower / (4 * size * size * Pi * Pi); + } + else if(prevUnits == LightUnits::EV100) + { + float ev100 = AreaLightEV100; + luminance = std::pow(2.0f, ev100 - 3.0f); + } + + // Set the new luminance onto the color + AreaLightColor.SetIntensity(luminance); + + // Update the other units + float angularRadius = std::atan2(size, distance); + float integralFactor = IlluminanceIntegral(angularRadius); + float illuminance = luminance * integralFactor; + AreaLightIlluminance.SetValue(illuminance); + + float luminousPower = luminance * (4 * size * size * Pi * Pi); + AreaLightLuminousPower.SetValue(luminousPower); + + float ev100 = std::log2(luminance) + 3.0f; + AreaLightEV100.SetValue(ev100); + + if(prevUnits != currUnits) + { + AreaLightColor.SetIntensityVisible(currUnits == LightUnits::Luminance); + AreaLightIlluminance.SetVisible(currUnits == LightUnits::Illuminance); + AreaLightLuminousPower.SetVisible(currUnits == LightUnits::LuminousPower); + AreaLightEV100.SetVisible(currUnits == LightUnits::EV100); + AreaLightIlluminanceDistance.SetVisible(currUnits == LightUnits::Illuminance); + + prevUnits = currUnits; + } + } + + void UpdateUI() + { + bool enableManualExposure = ExposureMode == ExposureModes::ManualSimple; + bool enableCameraExposure = ExposureMode == ExposureModes::Manual_SBS || + ExposureMode == ExposureModes::Manual_SOS; + bool enableAutoExposure = ExposureMode == ExposureModes::Automatic; + bool enableSimpleSkyParams = SkyMode == SkyModes::Simple; + bool enableProceduralSkyParams = SkyMode == SkyModes::Procedural; + bool useHejlTM = ToneMappingMode == ToneMappingModes::Hejl2015; + bool useHableTM = ToneMappingMode == ToneMappingModes::Hable; + bool useSGSettings = SGCount() > 0; + + ManualExposure.SetEditable(enableManualExposure); + ShutterSpeed.SetEditable(enableCameraExposure); + ISORating.SetEditable(enableCameraExposure); + KeyValue.SetEditable(enableAutoExposure); + AdaptationRate.SetEditable(enableAutoExposure); + SkyColor.SetEditable(enableSimpleSkyParams); + Turbidity.SetEditable(enableProceduralSkyParams); + GroundAlbedo.SetEditable(enableProceduralSkyParams); + + WhitePoint_Hejl.SetVisible(useHejlTM); + + WhitePoint_Hable.SetVisible(useHableTM); + ShoulderStrength.SetVisible(useHableTM); + LinearStrength.SetVisible(useHableTM); + LinearAngle.SetVisible(useHableTM); + ToeStrength.SetVisible(useHableTM); + + bool enableSunDirection = SunDirType == SunDirectionTypes::UnitVector; + bool enableHorizCoord = SunDirType == SunDirectionTypes::HorizontalCoordSystem; + + SunDirection.SetVisible(enableSunDirection); + SunAzimuth.SetVisible(enableHorizCoord); + SunElevation.SetVisible(enableHorizCoord); + + SGDiffuseMode.SetEditable(useSGSettings); + SolveMode.SetEditable(useSGSettings); + + if(AppSettings::HasSunDirChanged()) + { + if(SunDirType == SunDirectionTypes::UnitVector) + { + UpdateHorizontalCoords(); + } + else if(SunDirType == SunDirectionTypes::HorizontalCoordSystem) + { + UpdateUnitVector(); + } + } + + UpdateAreaLightUnits(); + } } \ No newline at end of file diff --git a/BakingLab/AppSettings.cs b/BakingLab/AppSettings.cs index 56a96a6..c03037c 100644 --- a/BakingLab/AppSettings.cs +++ b/BakingLab/AppSettings.cs @@ -1,817 +1,931 @@ -//================================================================================================= -// -// Baking Lab -// by MJP and David Neubelt -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -enum SunDirectionTypes -{ - [EnumLabel("Unit Vector")] - UnitVector, - - [EnumLabel("Horizontal Coordinate System")] - HorizontalCoordSystem, -} - -enum SkyModes -{ - [EnumLabel("None")] - None = 0, - - [EnumLabel("Procedural")] - Procedural, - - [EnumLabel("Simple")] - Simple, - - [EnumLabel("Ennis")] - CubeMapEnnis, - - [EnumLabel("Grace Cathedral")] - CubeMapGraceCathedral, - - [EnumLabel("Uffizi Cross")] - CubeMapUffizi -} - -enum ToneMappingModes -{ - [EnumLabel("Film Stock")] - FilmStock, - - [EnumLabel("Linear")] - Linear, - - [EnumLabel("ACES sRGB Monitor")] - ACES, - - [EnumLabel("Hejl 2015")] - Hejl2015, - - [EnumLabel("Hable (Uncharted2)")] - Hable, -} - -enum ExposureModes -{ - [EnumLabel("Manual (Simple)")] - ManualSimple = 0, - - [EnumLabel("Manual (SBS)")] - Manual_SBS = 1, - - [EnumLabel("Manual (SOS)")] - Manual_SOS = 2, - - [EnumLabel("Automatic")] - Automatic = 3 -} - -enum FStops -{ - [EnumLabel("f/1.8")] - FStop1Point8 = 0, - - [EnumLabel("f/2.0")] - FStop2Point0, - - [EnumLabel("f/2.2")] - FStop2Point2, - - [EnumLabel("f/2.5")] - FStop2Point5, - - [EnumLabel("f/2.8")] - FStop2Point8, - - [EnumLabel("f/3.2")] - FStop3Point2, - - [EnumLabel("f/3.5")] - FStop3Point5, - - [EnumLabel("f/4.0")] - FStop4Point0, - - [EnumLabel("f/4.5")] - FStop4Point5, - - [EnumLabel("f/5.0")] - FStop5Point0, - - [EnumLabel("f/5.6")] - FStop5Point6, - - [EnumLabel("f/6.3")] - FStop6Point3, - - [EnumLabel("f/7.1")] - FStop7Point1, - - [EnumLabel("f/8.0")] - FStop8Point0, - - [EnumLabel("f/9.0")] - FStop9Point0, - - [EnumLabel("f/10.0")] - FStop10Point0, - - [EnumLabel("f/11.0")] - FStop11Point0, - - [EnumLabel("f/13.0")] - FStop13Point0, - - [EnumLabel("f/14.0")] - FStop14Point0, - - [EnumLabel("f/16.0")] - FStop16Point0, - - [EnumLabel("f/18.0")] - FStop18Point0, - - [EnumLabel("f/20.0")] - FStop20Point0, - - [EnumLabel("f/22.0")] - FStop22Point0, -} - -enum ISORatings -{ - ISO100 = 0, - ISO200, - ISO400, - ISO800, -} - -enum ShutterSpeeds -{ - [EnumLabel("1s")] - ShutterSpeed1Over1 = 0, - - [EnumLabel("1/2s")] - ShutterSpeed1Over2, - - [EnumLabel("1/4s")] - ShutterSpeed1Over4, - - [EnumLabel("1/8s")] - ShutterSpeed1Over8, - - [EnumLabel("1/15s")] - ShutterSpeed1Over15, - - [EnumLabel("1/30s")] - ShutterSpeed1Over30, - - [EnumLabel("1/60s")] - ShutterSpeed1Over60, - - [EnumLabel("1/125s")] - ShutterSpeed1Over125, - - [EnumLabel("1/250s")] - ShutterSpeed1Over250, - - [EnumLabel("1/500s")] - ShutterSpeed1Over500, - - [EnumLabel("1/1000s")] - ShutterSpeed1Over1000, - - [EnumLabel("1/2000s")] - ShutterSpeed1Over2000, - - [EnumLabel("1/4000s")] - ShutterSpeed1Over4000, -} - -enum SampleModes -{ - Random = 0, - Stratified = 1, - Hammersley = 2, - UniformGrid = 3, - CMJ = 4, -} - -enum LightUnits -{ - Luminance = 0, - Illuminance = 1, - LuminousPower = 2, - EV100 = 3 -} - -enum Scenes -{ - Box = 0, - - [EnumLabel("White Room")] - WhiteRoom = 1, - - Sponza = 2, -} - -enum MSAAModes -{ - [EnumLabel("None")] - MSAANone = 0, - - [EnumLabel("2x")] - MSAA2x, - - [EnumLabel("4x")] - MSAA4x, - - [EnumLabel("8x")] - MSAA8x, -} - -enum FilterTypes -{ - Box = 0, - Triangle, - Gaussian, - BlackmanHarris, - Smoothstep, - BSpline, -} - -enum JitterModes -{ - None, - Uniform2x, - Hammersley4x, - Hammersley8x, - Hammersley16x, -} - -enum BakeModes -{ - Diffuse = 0, - - [EnumLabel("Half-Life 2")] - HL2, - - [EnumLabel("L1 SH")] - SH4, - - [EnumLabel("L2 SH")] - SH9, - - [EnumLabel("L1 H-basis")] - H4, - - [EnumLabel("L2 H-basis")] - H6, - - SG5, - SG6, - SG9, - SG12, -} - -enum SolveModes -{ - [EnumLabel("Ad-Hoc Projection")] - Projection = 0, - - [EnumLabel("Least Squares")] - SVD, - - [EnumLabel("Non-Negative Least Squares")] - NNLS, -} - -enum SGDiffuseModes -{ - InnerProduct = 0, - Punctual, - - [EnumLabel("Fitted (Hill 16)")] - Fitted, -} - -public class Settings -{ - const float BaseSunSize = 0.27f; - - public class SunLight - { - [HelpText("Enables the sun light")] - bool EnableSun = true; - - [HelpText("Controls whether the sun is treated as a disc area light in the real-time shader")] - bool SunAreaLightApproximation = true; - - [HelpText("The color of the sun")] - Color SunTintColor = new Color(1.0f, 1.0f, 1.0f, 1.0f); - - [HelpText("Scale the intensity of the sun")] - [MinValue(0.0f)] - float SunIntensityScale = 1.0f; - - [HelpText("Angular radius of the sun in degrees")] - [MinValue(0.01f)] - [StepSize(0.001f)] - float SunSize = BaseSunSize; - - [UseAsShaderConstant(false)] - bool NormalizeSunIntensity = false; - - [HelpText("Input direction type for the sun")] - SunDirectionTypes SunDirType = SunDirectionTypes.HorizontalCoordSystem; - - [HelpText("Director of the sun")] - Direction SunDirection = new Direction(-0.75f, 0.977f, -0.4f); - - [HelpText("Angle around the horizon")] - [MinValue(0.0f)] - [MaxValue(360.0f)] - [StepSize(0.1f)] - float SunAzimuth; - - [HelpText("Elevation of sun from ground. 0 degrees is aligned on the horizon while 90 degrees is directly overhead")] - [MinValue(0.0f)] - [MaxValue(90.0f)] - [StepSize(0.1f)] - float SunElevation; - } - - public class Sky - { - [HelpText("Controls the sky used for GI baking and background rendering")] - [UseAsShaderConstant(false)] - SkyModes SkyMode = SkyModes.Procedural; - - [HelpText("The color of the simple sky")] - [MinValue(0.0f)] - [MaxValue(1000000.0f)] - [StepSize(0.1f)] - [HDR(true)] - [ColorUnit(ColorUnit.Luminance)] - [UseAsShaderConstant(false)] - Color SkyColor = new Color(0.2f, 0.5f, 1.0f, 7000.0f); - - [MinValue(1.0f)] - [MaxValue(10.0f)] - [UseAsShaderConstant(false)] - float Turbidity = 2.0f; - - [HDR(false)] - [UseAsShaderConstant(false)] - Color GroundAlbedo = new Color(0.5f, 0.5f, 0.5f); - } - - [ExpandGroup(false)] - public class AreaLight - { - [HelpText("Enables the area light during baking and ground truth rendering")] - bool EnableAreaLight = false; - - [DisplayName("Color")] - [MinValue(0.0f)] - [StepSize(0.1f)] - [HDR(true)] - [ColorUnit(ColorUnit.Luminance)] - [HelpText("The color of the area light")] - Color AreaLightColor = new Color(1.0f, 1.0f, 1.0f, 1000000.0f); - - [DisplayName("Color Intensity (lux)")] - [MinValue(0.0f)] - [Visible(false)] - [UseAsShaderConstant(false)] - float AreaLightIlluminance = 1.0f; - - [DisplayName("Color Intensity (lm)")] - [MinValue(0.0f)] - [Visible(false)] - [UseAsShaderConstant(false)] - float AreaLightLuminousPower = 1.0f; - - [DisplayName("Color Intensity (EV100)")] - [MinValue(-64.0f)] - [MaxValue(64.0f)] - [Visible(false)] - [UseAsShaderConstant(false)] - float AreaLightEV100 = 0.0f; - - [UseAsShaderConstant(false)] - [DisplayName("Units")] - LightUnits AreaLightUnits = LightUnits.Luminance; - - [DisplayName("Illuminance Distance")] - [UseAsShaderConstant(false)] - [Visible(false)] - float AreaLightIlluminanceDistance = 10.0f; - - [DisplayName("Size")] - [MinValue(0.01f)] - [MaxValue(10.0f)] - [StepSize(0.01f)] - [HelpText("The radius of the area light")] - float AreaLightSize = 0.5f; - - [DisplayName("Position X")] - [MinValue(-100.0f)] - [MaxValue(100.0f)] - [StepSize(0.01f)] - [HelpText("The X coordinate of the area light")] - float AreaLightX = 0.0f; - - [DisplayName("Position Y")] - [MinValue(-100.0f)] - [MaxValue(100.0f)] - [StepSize(0.01f)] - [HelpText("The Y coordinate of the area light")] - float AreaLightY = 5.0f; - - [DisplayName("Position Z")] - [MinValue(-100.0f)] - [MaxValue(100.0f)] - [StepSize(0.01f)] - [HelpText("The Z coordinate of the area light")] - float AreaLightZ = 0.0f; - - [DisplayName("Shadow Bias")] - [MinValue(0.0f)] - [MaxValue(1.0f)] - [StepSize(0.001f)] - float AreaLightShadowBias = 0.001f; - - [HelpText("Bakes the direct contribution from the area light into the light map")] - bool BakeDirectAreaLight = false; - - bool EnableAreaLightShadows = true; - } - - [ExpandGroup(false)] - public class CameraControls - { - [HelpText("Specifies how exposure should be controled")] - ExposureModes ExposureMode = ExposureModes.Manual_SBS; - - [MinValue(-32.0f)] - [MaxValue(32.0f)] - [StepSize(0.01f)] - [HelpText("Manual exposure value when auto-exposure is disabled")] - float ManualExposure = -16.0f; - - [DisplayName("Aperture")] - [UseAsShaderConstant(false)] - FStops ApertureSize = FStops.FStop16Point0; - - [DisplayName("ISO Rating")] - [UseAsShaderConstant(false)] - ISORatings ISORating = ISORatings.ISO100; - - [DisplayName("Shutter Speed")] - [UseAsShaderConstant(false)] - ShutterSpeeds ShutterSpeed = ShutterSpeeds.ShutterSpeed1Over125; - - [DisplayName("Film Size(mm)")] - [MinValue(1.0f)] - [MaxValue(100.0f)] - [StepSize(0.1f)] - [ConversionScale(0.001f)] - float FilmSize = 35.0f; - - [DisplayName("Focal Length(mm)")] - [MinValue(1.0f)] - [MaxValue(200.0f)] - [StepSize(0.1f)] - [ConversionScale(0.001f)] - float FocalLength = 35.0f; - - [MinValue(1.0f)] - [MaxValue(100.0f)] - [StepSize(0.1f)] - float FocusDistance = 10.0f; - - [DisplayName("Num Aperture Blades")] - [MinValue(5)] - [MaxValue(9)] - int NumBlades = 5; - - [DisplayName("Enable DOF")] - [UseAsShaderConstant(false)] - bool EnableDOF = false; - - [DisplayName("Auto-Exposure Key Value")] - [MinValue(0.0f)] - [MaxValue(0.5f)] - [StepSize(0.01f)] - [HelpText("Parameter that biases the result of the auto-exposure pass")] - float KeyValue = 0.115f; - - [DisplayName("Adaptation Rate")] - [MinValue(0.0f)] - [MaxValue(4.0f)] - [StepSize(0.01f)] - [HelpText("Controls how quickly auto-exposure adapts to changes in scene brightness")] - float AdaptationRate = 0.5f; - - // Virtuals - [VirtualSetting("ApertureFNumber_()")] - [Visible(false)] - float ApertureFNumber; - - [VirtualSetting("ApertureWidth_()")] - [Visible(false)] - float ApertureWidth; - - [VirtualSetting("ShutterSpeedValue_()")] - [Visible(false)] - float ShutterSpeedValue; - - [VirtualSetting("ISO_()")] - [Visible(false)] - float ISO; - - [VirtualSetting("BokehPolygonAmount_()")] - [Visible(false)] - float BokehPolygonAmount; - } - - [ExpandGroup(false)] - public class ToneMapping - { - [DisplayName("Tone Mapping Operator")] - ToneMappingModes ToneMappingMode = ToneMappingModes.ACES; - - [MinValue(0.01f)] - [StepSize(0.01f)] - [DisplayName("White Point (Hejl2015)")] - float WhitePoint_Hejl = 1.0f; - - [MinValue(0.01f)] - [StepSize(0.01f)] - float ShoulderStrength = 4.0f; - - [MinValue(0.01f)] - [StepSize(0.01f)] - float LinearStrength = 5.0f; - - [MinValue(0.01f)] - [StepSize(0.01f)] - float LinearAngle = 0.12f; - - [MinValue(0.01f)] - [StepSize(0.01f)] - float ToeStrength = 13.0f; - - [MinValue(0.01f)] - [StepSize(0.01f)] - [DisplayName("White Point (Hable)")] - float WhitePoint_Hable = 6.0f; - } - - [ExpandGroup(false)] - public class AntiAliasing - { - MSAAModes MSAAMode = MSAAModes.MSAA4x; - - FilterTypes FilterType = FilterTypes.Smoothstep; - - [MinValue(0.0f)] - [MaxValue(6.0f)] - [StepSize(0.01f)] - float FilterSize = 2.0f; - - [MinValue(0.01f)] - [MaxValue(1.0f)] - [StepSize(0.01f)] - float GaussianSigma = 0.5f; - - [UseAsShaderConstant(false)] - bool EnableTemporalAA = true; - - [UseAsShaderConstant(false)] - JitterModes JitterMode = JitterModes.Hammersley4x; - - [MinValue(0.0f)] - [UseAsShaderConstant(false)] - float JitterScale = 1.0f; - } - - const int MaxSGCount = 12; - const int MaxBasisCount = MaxSGCount; - - [ExpandGroup(false)] - [DisplayName("SG Settings")] - public class SGSettings - { - [DisplayName("SG Diffuse Mode")] - SGDiffuseModes SGDiffuseMode = SGDiffuseModes.Fitted; - - [DisplayName("Use ASG Warp")] - bool UseASGWarp = true; - } - - [ExpandGroup(false)] - public class Baking - { - [DisplayName("Light Map Resolution")] - [HelpText("The texture resolution of the light map")] - [MinValue(64)] - [MaxValue(4096)] - int LightMapResolution = 256; - - [HelpText("The square root of the number of sample rays to use for baking GI")] - [MinValue(1)] - [MaxValue(100)] - [UseAsShaderConstant(false)] - [DisplayName("Sqrt Num Samples")] - int NumBakeSamples = 25; - - [UseAsShaderConstant(false)] - [DisplayName("Sample Mode")] - SampleModes BakeSampleMode = SampleModes.CMJ; - - [HelpText("Maximum path length (bounces + 2) to use for baking GI (set to -1 for infinite)")] - [UseAsShaderConstant(false)] - [MinValue(-1)] - int MaxBakePathLength = -1; - - [HelpText("Path length at which Russian roulette kicks in (-1 to disable)")] - [UseAsShaderConstant(false)] - [MinValue(-1)] - [DisplayName("Russian Roullette Depth")] - int BakeRussianRouletteDepth = 4; - - [HelpText("Maximum probability for continuing when Russian roulette is used")] - [UseAsShaderConstant(false)] - [MinValue(0.0f)] - [MaxValue(1.0f)] - [StepSize(0.01f)] - [DisplayName("Russian Roullette Probability")] - float BakeRussianRouletteProbability = 0.5f; - - BakeModes BakeMode = BakeModes.SG9; - - SolveModes SolveMode = SolveModes.NNLS; - } - - [ExpandGroup(false)] - public class Scene - { - [UseAsShaderConstant(false)] - Scenes CurrentScene = Scenes.Box; - - [DisplayName("Enable Diffuse")] - [HelpText("Enables diffuse lighting")] - bool EnableDiffuse = true; - - [DisplayName("Enable Specular")] - [HelpText("Enables specular lighting")] - bool EnableSpecular = true; - - [DisplayName("Enable Direct Lighting")] - [HelpText("Enables direct lighting")] - bool EnableDirectLighting = true; - - [DisplayName("Enable Indirect Lighting")] - [HelpText("Enables indirect lighting")] - bool EnableIndirectLighting = true; - - [DisplayName("Enable Indirect Diffuse")] - [HelpText("Enables indirect diffuse lighting")] - bool EnableIndirectDiffuse = true; - - [DisplayName("Enable Indirect Specular")] - [HelpText("Enables indirect specular lighting")] - bool EnableIndirectSpecular = true; - - [DisplayName("Enable Albedo Maps")] - [HelpText("Enables albedo maps")] - bool EnableAlbedoMaps = true; - - [DisplayName("Enable Normal Maps")] - [HelpText("Enables normal maps")] - bool EnableNormalMaps = true; - - [DisplayName("Normal Map Intensity")] - [MinValue(0.0f)] - [MaxValue(1.0f)] - [StepSize(0.01f)] - [HelpText("Intensity of the normal map")] - float NormalMapIntensity = 0.5f; - - [DisplayName("Diffuse Albedo Scale")] - [MinValue(0.0f)] - [StepSize(0.01f)] - [HelpText("Global scale applied to all material diffuse albedo values")] - float DiffuseAlbedoScale = 0.5f; - - [DisplayName("Specular Roughness Scale")] - [MinValue(0.01f)] - [StepSize(0.01f)] - [HelpText("Global scale applied to all material roughness values")] - float RoughnessScale = 2.0f; - } - - [ExpandGroup(false)] - public class GroundTruth - { - [DisplayName("Show Ground Truth")] - [HelpText("If enabled, shows a ground truth image rendered on the CPU")] - [UseAsShaderConstant(false)] - bool ShowGroundTruth = false; - - [HelpText("The square root of the number of per-pixel sample rays to use for ground truth rendering")] - [UseAsShaderConstant(false)] - [MinValue(1)] - [MaxValue(100)] - [DisplayName("Sqrt Num Samples")] - int NumRenderSamples = 4; - - [UseAsShaderConstant(false)] - [DisplayName("Sample Mode")] - SampleModes RenderSampleMode = SampleModes.CMJ; - - [HelpText("Maximum path length (bounces) to use for ground truth rendering (set to -1 for infinite)")] - [UseAsShaderConstant(false)] - [MinValue(-1)] - [DisplayName("Max Path Length")] - int MaxRenderPathLength = -1; - - [HelpText("Path length at which Russian roulette kicks in (-1 to disable)")] - [UseAsShaderConstant(false)] - [MinValue(-1)] - [DisplayName("Russian Roullette Depth")] - int RenderRussianRouletteDepth = 4; - - [HelpText("Maximum probability for continuing when Russian roulette is used")] - [UseAsShaderConstant(false)] - [MinValue(0.0f)] - [MaxValue(1.0f)] - [StepSize(0.01f)] - [DisplayName("Russian Roullette Probability")] - float RenderRussianRouletteProbability = 0.5f; - - [DisplayName("Enable Bounce Specular")] - [HelpText("Enables specular calculations after the first hit")] - [UseAsShaderConstant(false)] - bool EnableRenderBounceSpecular = false; - } - - [ExpandGroup(false)] - public class PostProcessing - { - [DisplayName("Bloom Exposure Offset")] - [MinValue(-10.0f)] - [MaxValue(0.0f)] - [StepSize(0.01f)] - [HelpText("Exposure offset applied to generate the input of the bloom pass")] - float BloomExposure = -4.0f; - - [DisplayName("Bloom Magnitude")] - [MinValue(0.0f)] - [MaxValue(2.0f)] - [StepSize(0.01f)] - [HelpText("Scale factor applied to the bloom results when combined with tone-mapped result")] - float BloomMagnitude = 1.0f; - - [DisplayName("Bloom Blur Sigma")] - [MinValue(0.5f)] - [MaxValue(2.5f)] - [StepSize(0.01f)] - [HelpText("Sigma parameter of the Gaussian filter used in the bloom pass")] - float BloomBlurSigma = 2.5f; - } - - [ExpandGroup(false)] - public class Debug - { - [UseAsShaderConstant(false)] - bool EnableLuminancePicker = false; - - [UseAsShaderConstant(false)] - bool ShowBakeDataVisualizer = false; - - bool ViewIndirectSpecular = false; - - [DisplayName("Save Light Settings")] - [HelpText("Saves the lighting settings to a file")] - Button SaveLightSettings; - - [DisplayName("Load Light Settings")] - [HelpText("Loads the lighting settings from a file")] - Button LoadLightSettings; - - [DisplayName("Save EXR Screenshot")] - [HelpText("Captures the current screen image in EXR format")] - Button SaveEXRScreenshot; - - [UseAsShaderConstant(false)] - bool ShowSunIntensity = false; - } +//================================================================================================= +// +// Baking Lab +// by MJP and David Neubelt +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +enum SunDirectionTypes +{ + [EnumLabel("Unit Vector")] + UnitVector, + + [EnumLabel("Horizontal Coordinate System")] + HorizontalCoordSystem, +} + +enum SkyModes +{ + [EnumLabel("None")] + None = 0, + + [EnumLabel("Procedural")] + Procedural, + + [EnumLabel("Simple")] + Simple, + + [EnumLabel("Ennis")] + CubeMapEnnis, + + [EnumLabel("Grace Cathedral")] + CubeMapGraceCathedral, + + [EnumLabel("Uffizi Cross")] + CubeMapUffizi +} + +enum ToneMappingModes +{ + [EnumLabel("Film Stock")] + FilmStock, + + [EnumLabel("Linear")] + Linear, + + [EnumLabel("ACES sRGB Monitor")] + ACES, + + [EnumLabel("Hejl 2015")] + Hejl2015, + + [EnumLabel("Hable (Uncharted2)")] + Hable, +} + +enum ExposureModes +{ + [EnumLabel("Manual (Simple)")] + ManualSimple = 0, + + [EnumLabel("Manual (SBS)")] + Manual_SBS = 1, + + [EnumLabel("Manual (SOS)")] + Manual_SOS = 2, + + [EnumLabel("Automatic")] + Automatic = 3 +} + +enum FStops +{ + [EnumLabel("f/1.8")] + FStop1Point8 = 0, + + [EnumLabel("f/2.0")] + FStop2Point0, + + [EnumLabel("f/2.2")] + FStop2Point2, + + [EnumLabel("f/2.5")] + FStop2Point5, + + [EnumLabel("f/2.8")] + FStop2Point8, + + [EnumLabel("f/3.2")] + FStop3Point2, + + [EnumLabel("f/3.5")] + FStop3Point5, + + [EnumLabel("f/4.0")] + FStop4Point0, + + [EnumLabel("f/4.5")] + FStop4Point5, + + [EnumLabel("f/5.0")] + FStop5Point0, + + [EnumLabel("f/5.6")] + FStop5Point6, + + [EnumLabel("f/6.3")] + FStop6Point3, + + [EnumLabel("f/7.1")] + FStop7Point1, + + [EnumLabel("f/8.0")] + FStop8Point0, + + [EnumLabel("f/9.0")] + FStop9Point0, + + [EnumLabel("f/10.0")] + FStop10Point0, + + [EnumLabel("f/11.0")] + FStop11Point0, + + [EnumLabel("f/13.0")] + FStop13Point0, + + [EnumLabel("f/14.0")] + FStop14Point0, + + [EnumLabel("f/16.0")] + FStop16Point0, + + [EnumLabel("f/18.0")] + FStop18Point0, + + [EnumLabel("f/20.0")] + FStop20Point0, + + [EnumLabel("f/22.0")] + FStop22Point0, +} + +enum ISORatings +{ + ISO100 = 0, + ISO200, + ISO400, + ISO800, +} + +enum ShutterSpeeds +{ + [EnumLabel("1s")] + ShutterSpeed1Over1 = 0, + + [EnumLabel("1/2s")] + ShutterSpeed1Over2, + + [EnumLabel("1/4s")] + ShutterSpeed1Over4, + + [EnumLabel("1/8s")] + ShutterSpeed1Over8, + + [EnumLabel("1/15s")] + ShutterSpeed1Over15, + + [EnumLabel("1/30s")] + ShutterSpeed1Over30, + + [EnumLabel("1/60s")] + ShutterSpeed1Over60, + + [EnumLabel("1/125s")] + ShutterSpeed1Over125, + + [EnumLabel("1/250s")] + ShutterSpeed1Over250, + + [EnumLabel("1/500s")] + ShutterSpeed1Over500, + + [EnumLabel("1/1000s")] + ShutterSpeed1Over1000, + + [EnumLabel("1/2000s")] + ShutterSpeed1Over2000, + + [EnumLabel("1/4000s")] + ShutterSpeed1Over4000, +} + +enum SampleModes +{ + Random = 0, + Stratified = 1, + Hammersley = 2, + UniformGrid = 3, + CMJ = 4, +} + +enum LightUnits +{ + Luminance = 0, + Illuminance = 1, + LuminousPower = 2, + EV100 = 3 +} + +enum Scenes +{ + Box = 0, + + [EnumLabel("White Room")] + WhiteRoom = 1, + + Sponza = 2, +} + +enum MSAAModes +{ + [EnumLabel("None")] + MSAANone = 0, + + [EnumLabel("2x")] + MSAA2x, + + [EnumLabel("4x")] + MSAA4x, + + [EnumLabel("8x")] + MSAA8x, +} + +enum FilterTypes +{ + Box = 0, + Triangle, + Gaussian, + BlackmanHarris, + Smoothstep, + BSpline, +} + +enum JitterModes +{ + None, + Uniform2x, + Hammersley4x, + Hammersley8x, + Hammersley16x, +} + +enum BakeModes +{ + Diffuse = 0, + + [EnumLabel("Half-Life 2")] + HL2, + + [EnumLabel("L1 SH")] + SH4, + + [EnumLabel("L2 SH")] + SH9, + + [EnumLabel("L1 H-basis")] + H4, + + [EnumLabel("L2 H-basis")] + H6, + + SG5, + SG6, + SG9, + SG12, +} + +enum SolveModes +{ + [EnumLabel("Ad-Hoc Projection")] + Projection = 0, + + [EnumLabel("Least Squares")] + SVD, + + [EnumLabel("Non-Negative Least Squares")] + NNLS, +} + +enum SGDiffuseModes +{ + InnerProduct = 0, + Punctual, + + [EnumLabel("Fitted (Hill 16)")] + Fitted, +} + +enum ProbeModes +{ + CubeMap, + AmbientCube, + + [EnumLabel("L1 SH")] + L1_SH, + + [EnumLabel("L2 SH")] + L2_SH, +} + +enum VoxelVisualizerModes +{ + None, + Geometry, + RayMarch +}; + +public class Settings +{ + const float BaseSunSize = 0.27f; + + public class SunLight + { + [HelpText("Enables the sun light")] + bool EnableSun = true; + + [HelpText("Controls whether the sun is treated as a disc area light in the real-time shader")] + bool SunAreaLightApproximation = true; + + [HelpText("The color of the sun")] + Color SunTintColor = new Color(1.0f, 1.0f, 1.0f, 1.0f); + + [HelpText("Scale the intensity of the sun")] + [MinValue(0.0f)] + float SunIntensityScale = 1.0f; + + [HelpText("Angular radius of the sun in degrees")] + [MinValue(0.01f)] + [StepSize(0.001f)] + float SunSize = BaseSunSize; + + [UseAsShaderConstant(false)] + bool NormalizeSunIntensity = false; + + [HelpText("Input direction type for the sun")] + SunDirectionTypes SunDirType = SunDirectionTypes.HorizontalCoordSystem; + + [HelpText("Director of the sun")] + Direction SunDirection = new Direction(-0.75f, 0.977f, -0.4f); + + [HelpText("Angle around the horizon")] + [MinValue(0.0f)] + [MaxValue(360.0f)] + [StepSize(0.1f)] + float SunAzimuth; + + [HelpText("Elevation of sun from ground. 0 degrees is aligned on the horizon while 90 degrees is directly overhead")] + [MinValue(0.0f)] + [MaxValue(90.0f)] + [StepSize(0.1f)] + float SunElevation; + } + + public class Sky + { + [HelpText("Controls the sky used for GI baking and background rendering")] + [UseAsShaderConstant(false)] + SkyModes SkyMode = SkyModes.Procedural; + + [HelpText("The color of the simple sky")] + [MinValue(0.0f)] + [MaxValue(1000000.0f)] + [StepSize(0.1f)] + [HDR(true)] + [ColorUnit(ColorUnit.Luminance)] + [UseAsShaderConstant(false)] + Color SkyColor = new Color(0.2f, 0.5f, 1.0f, 7000.0f); + + [MinValue(1.0f)] + [MaxValue(10.0f)] + [UseAsShaderConstant(false)] + float Turbidity = 2.0f; + + [HDR(false)] + [UseAsShaderConstant(false)] + Color GroundAlbedo = new Color(0.5f, 0.5f, 0.5f); + } + + [ExpandGroup(false)] + public class AreaLight + { + [HelpText("Enables the area light during baking and ground truth rendering")] + bool EnableAreaLight = false; + + [DisplayName("Color")] + [MinValue(0.0f)] + [StepSize(0.1f)] + [HDR(true)] + [ColorUnit(ColorUnit.Luminance)] + [HelpText("The color of the area light")] + Color AreaLightColor = new Color(1.0f, 1.0f, 1.0f, 1000000.0f); + + [DisplayName("Color Intensity (lux)")] + [MinValue(0.0f)] + [Visible(false)] + [UseAsShaderConstant(false)] + float AreaLightIlluminance = 1.0f; + + [DisplayName("Color Intensity (lm)")] + [MinValue(0.0f)] + [Visible(false)] + [UseAsShaderConstant(false)] + float AreaLightLuminousPower = 1.0f; + + [DisplayName("Color Intensity (EV100)")] + [MinValue(-64.0f)] + [MaxValue(64.0f)] + [Visible(false)] + [UseAsShaderConstant(false)] + float AreaLightEV100 = 0.0f; + + [UseAsShaderConstant(false)] + [DisplayName("Units")] + LightUnits AreaLightUnits = LightUnits.Luminance; + + [DisplayName("Illuminance Distance")] + [UseAsShaderConstant(false)] + [Visible(false)] + float AreaLightIlluminanceDistance = 10.0f; + + [DisplayName("Size")] + [MinValue(0.01f)] + [MaxValue(10.0f)] + [StepSize(0.01f)] + [HelpText("The radius of the area light")] + float AreaLightSize = 0.5f; + + [DisplayName("Position X")] + [MinValue(-100.0f)] + [MaxValue(100.0f)] + [StepSize(0.01f)] + [HelpText("The X coordinate of the area light")] + float AreaLightX = 0.0f; + + [DisplayName("Position Y")] + [MinValue(-100.0f)] + [MaxValue(100.0f)] + [StepSize(0.01f)] + [HelpText("The Y coordinate of the area light")] + float AreaLightY = 5.0f; + + [DisplayName("Position Z")] + [MinValue(-100.0f)] + [MaxValue(100.0f)] + [StepSize(0.01f)] + [HelpText("The Z coordinate of the area light")] + float AreaLightZ = 0.0f; + + [DisplayName("Shadow Bias")] + [MinValue(0.0f)] + [MaxValue(1.0f)] + [StepSize(0.001f)] + float AreaLightShadowBias = 0.001f; + + [HelpText("Bakes the direct contribution from the area light into the light map")] + bool BakeDirectAreaLight = false; + + bool EnableAreaLightShadows = true; + } + + [ExpandGroup(false)] + public class CameraControls + { + [HelpText("Specifies how exposure should be controled")] + ExposureModes ExposureMode = ExposureModes.Manual_SBS; + + [MinValue(-32.0f)] + [MaxValue(32.0f)] + [StepSize(0.01f)] + [HelpText("Manual exposure value when auto-exposure is disabled")] + float ManualExposure = -16.0f; + + [DisplayName("Aperture")] + [UseAsShaderConstant(false)] + FStops ApertureSize = FStops.FStop16Point0; + + [DisplayName("ISO Rating")] + [UseAsShaderConstant(false)] + ISORatings ISORating = ISORatings.ISO100; + + [DisplayName("Shutter Speed")] + [UseAsShaderConstant(false)] + ShutterSpeeds ShutterSpeed = ShutterSpeeds.ShutterSpeed1Over125; + + [DisplayName("Film Size(mm)")] + [MinValue(1.0f)] + [MaxValue(100.0f)] + [StepSize(0.1f)] + [ConversionScale(0.001f)] + float FilmSize = 35.0f; + + [DisplayName("Focal Length(mm)")] + [MinValue(1.0f)] + [MaxValue(200.0f)] + [StepSize(0.1f)] + [ConversionScale(0.001f)] + float FocalLength = 35.0f; + + [MinValue(1.0f)] + [MaxValue(100.0f)] + [StepSize(0.1f)] + float FocusDistance = 10.0f; + + [DisplayName("Num Aperture Blades")] + [MinValue(5)] + [MaxValue(9)] + int NumBlades = 5; + + [DisplayName("Enable DOF")] + [UseAsShaderConstant(false)] + bool EnableDOF = false; + + [DisplayName("Auto-Exposure Key Value")] + [MinValue(0.0f)] + [MaxValue(0.5f)] + [StepSize(0.01f)] + [HelpText("Parameter that biases the result of the auto-exposure pass")] + float KeyValue = 0.115f; + + [DisplayName("Adaptation Rate")] + [MinValue(0.0f)] + [MaxValue(4.0f)] + [StepSize(0.01f)] + [HelpText("Controls how quickly auto-exposure adapts to changes in scene brightness")] + float AdaptationRate = 0.5f; + + // Virtuals + [VirtualSetting("ApertureFNumber_()")] + [Visible(false)] + float ApertureFNumber; + + [VirtualSetting("ApertureWidth_()")] + [Visible(false)] + float ApertureWidth; + + [VirtualSetting("ShutterSpeedValue_()")] + [Visible(false)] + float ShutterSpeedValue; + + [VirtualSetting("ISO_()")] + [Visible(false)] + float ISO; + + [VirtualSetting("BokehPolygonAmount_()")] + [Visible(false)] + float BokehPolygonAmount; + } + + [ExpandGroup(false)] + public class ToneMapping + { + [DisplayName("Tone Mapping Operator")] + ToneMappingModes ToneMappingMode = ToneMappingModes.ACES; + + [MinValue(0.01f)] + [StepSize(0.01f)] + [DisplayName("White Point (Hejl2015)")] + float WhitePoint_Hejl = 1.0f; + + [MinValue(0.01f)] + [StepSize(0.01f)] + float ShoulderStrength = 4.0f; + + [MinValue(0.01f)] + [StepSize(0.01f)] + float LinearStrength = 5.0f; + + [MinValue(0.01f)] + [StepSize(0.01f)] + float LinearAngle = 0.12f; + + [MinValue(0.01f)] + [StepSize(0.01f)] + float ToeStrength = 13.0f; + + [MinValue(0.01f)] + [StepSize(0.01f)] + [DisplayName("White Point (Hable)")] + float WhitePoint_Hable = 6.0f; + } + + [ExpandGroup(false)] + public class AntiAliasing + { + MSAAModes MSAAMode = MSAAModes.MSAA4x; + + FilterTypes FilterType = FilterTypes.Smoothstep; + + [MinValue(0.0f)] + [MaxValue(6.0f)] + [StepSize(0.01f)] + float FilterSize = 2.0f; + + [MinValue(0.01f)] + [MaxValue(1.0f)] + [StepSize(0.01f)] + float GaussianSigma = 0.5f; + + [UseAsShaderConstant(false)] + bool EnableTemporalAA = true; + + [UseAsShaderConstant(false)] + JitterModes JitterMode = JitterModes.Hammersley4x; + + [MinValue(0.0f)] + [UseAsShaderConstant(false)] + float JitterScale = 1.0f; + } + + const int MaxSGCount = 12; + const int MaxBasisCount = MaxSGCount; + + [ExpandGroup(false)] + [DisplayName("SG Settings")] + public class SGSettings + { + [DisplayName("SG Diffuse Mode")] + SGDiffuseModes SGDiffuseMode = SGDiffuseModes.Fitted; + + [DisplayName("Use ASG Warp")] + bool UseASGWarp = true; + } + + [ExpandGroup(false)] + public class Baking + { + [DisplayName("Light Map Resolution")] + [HelpText("The texture resolution of the light map")] + [MinValue(64)] + [MaxValue(4096)] + int LightMapResolution = 256; + + [HelpText("The square root of the number of sample rays to use for baking GI")] + [MinValue(1)] + [MaxValue(100)] + [UseAsShaderConstant(false)] + [DisplayName("Sqrt Num Samples")] + int NumBakeSamples = 25; + + [UseAsShaderConstant(false)] + [DisplayName("Sample Mode")] + SampleModes BakeSampleMode = SampleModes.CMJ; + + [HelpText("Maximum path length (bounces + 2) to use for baking GI (set to -1 for infinite)")] + [UseAsShaderConstant(false)] + [MinValue(-1)] + int MaxBakePathLength = -1; + + [HelpText("Path length at which Russian roulette kicks in (-1 to disable)")] + [UseAsShaderConstant(false)] + [MinValue(-1)] + [DisplayName("Russian Roullette Depth")] + int BakeRussianRouletteDepth = 4; + + [HelpText("Maximum probability for continuing when Russian roulette is used")] + [UseAsShaderConstant(false)] + [MinValue(0.0f)] + [MaxValue(1.0f)] + [StepSize(0.01f)] + [DisplayName("Russian Roullette Probability")] + float BakeRussianRouletteProbability = 0.5f; + + BakeModes BakeMode = BakeModes.H4; + + SolveModes SolveMode = SolveModes.NNLS; + } + + [ExpandGroup(true)] + public class Probes + { + bool UseProbes = true; + + ProbeModes ProbeMode = ProbeModes.CubeMap; + + [MinValue(1)] + [MaxValue(2048)] + int ProbeResX = 4; + + [MinValue(1)] + [MaxValue(2048)] + int ProbeResY = 4; + + [MinValue(1)] + [MaxValue(2048)] + int ProbeResZ = 4; + + [MinValue(1)] + [MaxValue(4096)] + int ProbeCubemapCaptureRes = 256; + + [MinValue(1)] + [MaxValue(4096)] + int ProbeIrradianceCubemapRes = 16; + + [MinValue(1)] + [MaxValue(4096)] + int ProbeDistanceCubemapRes = 128; + + [UseAsShaderConstant(false)] + float SceneBoundsScale = 1.45f; + + bool WeightProbesByNormal = true; + + bool WeightProbesByVisibility = true; + + [MinValue(1.0f)] + [MaxValue(20.0f)] + float DistanceFilterSharpness = 10.0f; + + [MinValue(1)] + [MaxValue(64)] + int ProbeIntegrationSamples = 32; + + [MinValue(1)] + [MaxValue(64)] + int ProbeDistanceIntegrationSamples = 32; + } + + [ExpandGroup(false)] + public class VCT + { + bool BakeWithVCT = false; + + [MinValue(2)] + [MaxValue(2048)] + [DisplayName("Voxel Resolution")] + int VoxelResolution = 64; + } + + [ExpandGroup(false)] + public class Scene + { + [UseAsShaderConstant(false)] + Scenes CurrentScene = Scenes.Box; + + [DisplayName("Enable Diffuse")] + [HelpText("Enables diffuse lighting")] + bool EnableDiffuse = true; + + [DisplayName("Enable Specular")] + [HelpText("Enables specular lighting")] + bool EnableSpecular = true; + + [DisplayName("Enable Direct Lighting")] + [HelpText("Enables direct lighting")] + bool EnableDirectLighting = true; + + [DisplayName("Enable Indirect Lighting")] + [HelpText("Enables indirect lighting")] + bool EnableIndirectLighting = true; + + [DisplayName("Enable Indirect Diffuse")] + [HelpText("Enables indirect diffuse lighting")] + bool EnableIndirectDiffuse = true; + + [DisplayName("Enable Indirect Specular")] + [HelpText("Enables indirect specular lighting")] + bool EnableIndirectSpecular = false; + + [DisplayName("Enable Albedo Maps")] + [HelpText("Enables albedo maps")] + bool EnableAlbedoMaps = true; + + [DisplayName("Enable Normal Maps")] + [HelpText("Enables normal maps")] + bool EnableNormalMaps = true; + + [DisplayName("Normal Map Intensity")] + [MinValue(0.0f)] + [MaxValue(1.0f)] + [StepSize(0.01f)] + [HelpText("Intensity of the normal map")] + float NormalMapIntensity = 0.5f; + + [DisplayName("Diffuse Albedo Scale")] + [MinValue(0.0f)] + [StepSize(0.01f)] + [HelpText("Global scale applied to all material diffuse albedo values")] + float DiffuseAlbedoScale = 0.5f; + + [DisplayName("Specular Roughness Scale")] + [MinValue(0.01f)] + [StepSize(0.01f)] + [HelpText("Global scale applied to all material roughness values")] + float RoughnessScale = 2.0f; + } + + [ExpandGroup(false)] + public class GroundTruth + { + [DisplayName("Show Ground Truth")] + [HelpText("If enabled, shows a ground truth image rendered on the CPU")] + [UseAsShaderConstant(false)] + bool ShowGroundTruth = false; + + [HelpText("The square root of the number of per-pixel sample rays to use for ground truth rendering")] + [UseAsShaderConstant(false)] + [MinValue(1)] + [MaxValue(100)] + [DisplayName("Sqrt Num Samples")] + int NumRenderSamples = 4; + + [UseAsShaderConstant(false)] + [DisplayName("Sample Mode")] + SampleModes RenderSampleMode = SampleModes.CMJ; + + [HelpText("Maximum path length (bounces) to use for ground truth rendering (set to -1 for infinite)")] + [UseAsShaderConstant(false)] + [MinValue(-1)] + [DisplayName("Max Path Length")] + int MaxRenderPathLength = -1; + + [HelpText("Path length at which Russian roulette kicks in (-1 to disable)")] + [UseAsShaderConstant(false)] + [MinValue(-1)] + [DisplayName("Russian Roullette Depth")] + int RenderRussianRouletteDepth = 4; + + [HelpText("Maximum probability for continuing when Russian roulette is used")] + [UseAsShaderConstant(false)] + [MinValue(0.0f)] + [MaxValue(1.0f)] + [StepSize(0.01f)] + [DisplayName("Russian Roullette Probability")] + float RenderRussianRouletteProbability = 0.5f; + + [DisplayName("Enable Bounce Specular")] + [HelpText("Enables specular calculations after the first hit")] + [UseAsShaderConstant(false)] + bool EnableRenderBounceSpecular = false; + } + + [ExpandGroup(false)] + public class PostProcessing + { + [DisplayName("Bloom Exposure Offset")] + [MinValue(-10.0f)] + [MaxValue(0.0f)] + [StepSize(0.01f)] + [HelpText("Exposure offset applied to generate the input of the bloom pass")] + float BloomExposure = -4.0f; + + [DisplayName("Bloom Magnitude")] + [MinValue(0.0f)] + [MaxValue(2.0f)] + [StepSize(0.01f)] + [HelpText("Scale factor applied to the bloom results when combined with tone-mapped result")] + float BloomMagnitude = 1.0f; + + [DisplayName("Bloom Blur Sigma")] + [MinValue(0.5f)] + [MaxValue(2.5f)] + [StepSize(0.01f)] + [HelpText("Sigma parameter of the Gaussian filter used in the bloom pass")] + float BloomBlurSigma = 2.5f; + } + + [ExpandGroup(true)] + public class Debug + { + [UseAsShaderConstant(false)] + bool EnableLuminancePicker = false; + + [UseAsShaderConstant(false)] + bool ShowBakeDataVisualizer = false; + + [UseAsShaderConstant(false)] + bool ShowProbeVisualizer = false; + + bool ViewIndirectDiffuse = false; + + bool ViewIndirectSpecular = false; + + [UseAsShaderConstant(false)] + VoxelVisualizerModes VoxelVisualizerMode = VoxelVisualizerModes.None; + + [MinValue(0)] + [MaxValue(16)] + int VoxelVisualizerMipLevel = 0; + + [DisplayName("Save Light Settings")] + [HelpText("Saves the lighting settings to a file")] + Button SaveLightSettings; + + [DisplayName("Load Light Settings")] + [HelpText("Loads the lighting settings from a file")] + Button LoadLightSettings; + + [DisplayName("Save EXR Screenshot")] + [HelpText("Captures the current screen image in EXR format")] + Button SaveEXRScreenshot; + + [UseAsShaderConstant(false)] + bool ShowSunIntensity = false; + + [UseAsShaderConstant(false)] + bool AlwaysRegenerateProbes = false; + + [UseAsShaderConstant(false)] + bool AlwaysRevoxelize = false; + + [MinValue(-100.0f)] + [MaxValue(100.0f)] + [UseAsShaderConstant(false)] + float SceneBoundsOffsetX = 0.0f; + + [MinValue(-100.0f)] + [MaxValue(100.0f)] + [UseAsShaderConstant(false)] + float SceneBoundsOffsetY = 0.0f; + + [MinValue(-100.0f)] + [MaxValue(100.0f)] + [UseAsShaderConstant(false)] + float SceneBoundsOffsetZ = 0.0f; + } } \ No newline at end of file diff --git a/BakingLab/AppSettings.h b/BakingLab/AppSettings.h index a1d941d..1b2f03a 100644 --- a/BakingLab/AppSettings.h +++ b/BakingLab/AppSettings.h @@ -1,590 +1,693 @@ -#pragma once - -#include -#include -#include - -using namespace SampleFramework11; - -enum class SunDirectionTypes -{ - UnitVector = 0, - HorizontalCoordSystem = 1, - - NumValues -}; - -typedef EnumSettingT SunDirectionTypesSetting; - -enum class SkyModes -{ - None = 0, - Procedural = 1, - Simple = 2, - CubeMapEnnis = 3, - CubeMapGraceCathedral = 4, - CubeMapUffizi = 5, - - NumValues -}; - -typedef EnumSettingT SkyModesSetting; - -enum class LightUnits -{ - Luminance = 0, - Illuminance = 1, - LuminousPower = 2, - EV100 = 3, - - NumValues -}; - -typedef EnumSettingT LightUnitsSetting; - -enum class ExposureModes -{ - ManualSimple = 0, - Manual_SBS = 1, - Manual_SOS = 2, - Automatic = 3, - - NumValues -}; - -typedef EnumSettingT ExposureModesSetting; - -enum class FStops -{ - FStop1Point8 = 0, - FStop2Point0 = 1, - FStop2Point2 = 2, - FStop2Point5 = 3, - FStop2Point8 = 4, - FStop3Point2 = 5, - FStop3Point5 = 6, - FStop4Point0 = 7, - FStop4Point5 = 8, - FStop5Point0 = 9, - FStop5Point6 = 10, - FStop6Point3 = 11, - FStop7Point1 = 12, - FStop8Point0 = 13, - FStop9Point0 = 14, - FStop10Point0 = 15, - FStop11Point0 = 16, - FStop13Point0 = 17, - FStop14Point0 = 18, - FStop16Point0 = 19, - FStop18Point0 = 20, - FStop20Point0 = 21, - FStop22Point0 = 22, - - NumValues -}; - -typedef EnumSettingT FStopsSetting; - -enum class ISORatings -{ - ISO100 = 0, - ISO200 = 1, - ISO400 = 2, - ISO800 = 3, - - NumValues -}; - -typedef EnumSettingT ISORatingsSetting; - -enum class ShutterSpeeds -{ - ShutterSpeed1Over1 = 0, - ShutterSpeed1Over2 = 1, - ShutterSpeed1Over4 = 2, - ShutterSpeed1Over8 = 3, - ShutterSpeed1Over15 = 4, - ShutterSpeed1Over30 = 5, - ShutterSpeed1Over60 = 6, - ShutterSpeed1Over125 = 7, - ShutterSpeed1Over250 = 8, - ShutterSpeed1Over500 = 9, - ShutterSpeed1Over1000 = 10, - ShutterSpeed1Over2000 = 11, - ShutterSpeed1Over4000 = 12, - - NumValues -}; - -typedef EnumSettingT ShutterSpeedsSetting; - -enum class ToneMappingModes -{ - FilmStock = 0, - Linear = 1, - ACES = 2, - Hejl2015 = 3, - Hable = 4, - - NumValues -}; - -typedef EnumSettingT ToneMappingModesSetting; - -enum class MSAAModes -{ - MSAANone = 0, - MSAA2x = 1, - MSAA4x = 2, - MSAA8x = 3, - - NumValues -}; - -typedef EnumSettingT MSAAModesSetting; - -enum class FilterTypes -{ - Box = 0, - Triangle = 1, - Gaussian = 2, - BlackmanHarris = 3, - Smoothstep = 4, - BSpline = 5, - - NumValues -}; - -typedef EnumSettingT FilterTypesSetting; - -enum class JitterModes -{ - None = 0, - Uniform2x = 1, - Hammersley4x = 2, - Hammersley8x = 3, - Hammersley16x = 4, - - NumValues -}; - -typedef EnumSettingT JitterModesSetting; - -enum class SGDiffuseModes -{ - InnerProduct = 0, - Punctual = 1, - Fitted = 2, - - NumValues -}; - -typedef EnumSettingT SGDiffuseModesSetting; - -enum class SampleModes -{ - Random = 0, - Stratified = 1, - Hammersley = 2, - UniformGrid = 3, - CMJ = 4, - - NumValues -}; - -typedef EnumSettingT SampleModesSetting; - -enum class BakeModes -{ - Diffuse = 0, - HL2 = 1, - SH4 = 2, - SH9 = 3, - H4 = 4, - H6 = 5, - SG5 = 6, - SG6 = 7, - SG9 = 8, - SG12 = 9, - - NumValues -}; - -typedef EnumSettingT BakeModesSetting; - -enum class SolveModes -{ - Projection = 0, - SVD = 1, - NNLS = 2, - - NumValues -}; - -typedef EnumSettingT SolveModesSetting; - -enum class Scenes -{ - Box = 0, - WhiteRoom = 1, - Sponza = 2, - - NumValues -}; - -typedef EnumSettingT ScenesSetting; - -namespace AppSettings -{ - static const float BaseSunSize = 0.2700f; - static const int64 MaxSGCount = 12; - static const int64 MaxBasisCount = 12; - - extern BoolSetting EnableSun; - extern BoolSetting SunAreaLightApproximation; - extern ColorSetting SunTintColor; - extern FloatSetting SunIntensityScale; - extern FloatSetting SunSize; - extern BoolSetting NormalizeSunIntensity; - extern SunDirectionTypesSetting SunDirType; - extern DirectionSetting SunDirection; - extern FloatSetting SunAzimuth; - extern FloatSetting SunElevation; - extern SkyModesSetting SkyMode; - extern ColorSetting SkyColor; - extern FloatSetting Turbidity; - extern ColorSetting GroundAlbedo; - extern BoolSetting EnableAreaLight; - extern ColorSetting AreaLightColor; - extern FloatSetting AreaLightIlluminance; - extern FloatSetting AreaLightLuminousPower; - extern FloatSetting AreaLightEV100; - extern LightUnitsSetting AreaLightUnits; - extern FloatSetting AreaLightIlluminanceDistance; - extern FloatSetting AreaLightSize; - extern FloatSetting AreaLightX; - extern FloatSetting AreaLightY; - extern FloatSetting AreaLightZ; - extern FloatSetting AreaLightShadowBias; - extern BoolSetting BakeDirectAreaLight; - extern BoolSetting EnableAreaLightShadows; - extern ExposureModesSetting ExposureMode; - extern FloatSetting ManualExposure; - extern FStopsSetting ApertureSize; - extern ISORatingsSetting ISORating; - extern ShutterSpeedsSetting ShutterSpeed; - extern FloatSetting FilmSize; - extern FloatSetting FocalLength; - extern FloatSetting FocusDistance; - extern IntSetting NumBlades; - extern BoolSetting EnableDOF; - extern FloatSetting KeyValue; - extern FloatSetting AdaptationRate; - extern FloatSetting ApertureFNumber; - extern FloatSetting ApertureWidth; - extern FloatSetting ShutterSpeedValue; - extern FloatSetting ISO; - extern FloatSetting BokehPolygonAmount; - extern ToneMappingModesSetting ToneMappingMode; - extern FloatSetting WhitePoint_Hejl; - extern FloatSetting ShoulderStrength; - extern FloatSetting LinearStrength; - extern FloatSetting LinearAngle; - extern FloatSetting ToeStrength; - extern FloatSetting WhitePoint_Hable; - extern MSAAModesSetting MSAAMode; - extern FilterTypesSetting FilterType; - extern FloatSetting FilterSize; - extern FloatSetting GaussianSigma; - extern BoolSetting EnableTemporalAA; - extern JitterModesSetting JitterMode; - extern FloatSetting JitterScale; - extern SGDiffuseModesSetting SGDiffuseMode; - extern BoolSetting UseASGWarp; - extern IntSetting LightMapResolution; - extern IntSetting NumBakeSamples; - extern SampleModesSetting BakeSampleMode; - extern IntSetting MaxBakePathLength; - extern IntSetting BakeRussianRouletteDepth; - extern FloatSetting BakeRussianRouletteProbability; - extern BakeModesSetting BakeMode; - extern SolveModesSetting SolveMode; - extern ScenesSetting CurrentScene; - extern BoolSetting EnableDiffuse; - extern BoolSetting EnableSpecular; - extern BoolSetting EnableDirectLighting; - extern BoolSetting EnableIndirectLighting; - extern BoolSetting EnableIndirectDiffuse; - extern BoolSetting EnableIndirectSpecular; - extern BoolSetting EnableAlbedoMaps; - extern BoolSetting EnableNormalMaps; - extern FloatSetting NormalMapIntensity; - extern FloatSetting DiffuseAlbedoScale; - extern FloatSetting RoughnessScale; - extern BoolSetting ShowGroundTruth; - extern IntSetting NumRenderSamples; - extern SampleModesSetting RenderSampleMode; - extern IntSetting MaxRenderPathLength; - extern IntSetting RenderRussianRouletteDepth; - extern FloatSetting RenderRussianRouletteProbability; - extern BoolSetting EnableRenderBounceSpecular; - extern FloatSetting BloomExposure; - extern FloatSetting BloomMagnitude; - extern FloatSetting BloomBlurSigma; - extern BoolSetting EnableLuminancePicker; - extern BoolSetting ShowBakeDataVisualizer; - extern BoolSetting ViewIndirectSpecular; - extern Button SaveLightSettings; - extern Button LoadLightSettings; - extern Button SaveEXRScreenshot; - extern BoolSetting ShowSunIntensity; - - struct AppSettingsCBuffer - { - bool32 EnableSun; - bool32 SunAreaLightApproximation; - Float4Align Float3 SunTintColor; - float SunIntensityScale; - float SunSize; - int32 SunDirType; - Float4Align Float3 SunDirection; - float SunAzimuth; - float SunElevation; - bool32 EnableAreaLight; - Float4Align Float3 AreaLightColor; - float AreaLightSize; - float AreaLightX; - float AreaLightY; - float AreaLightZ; - float AreaLightShadowBias; - bool32 BakeDirectAreaLight; - bool32 EnableAreaLightShadows; - int32 ExposureMode; - float ManualExposure; - float FilmSize; - float FocalLength; - float FocusDistance; - int32 NumBlades; - float KeyValue; - float AdaptationRate; - float ApertureFNumber; - float ApertureWidth; - float ShutterSpeedValue; - float ISO; - float BokehPolygonAmount; - int32 ToneMappingMode; - float WhitePoint_Hejl; - float ShoulderStrength; - float LinearStrength; - float LinearAngle; - float ToeStrength; - float WhitePoint_Hable; - int32 MSAAMode; - int32 FilterType; - float FilterSize; - float GaussianSigma; - int32 SGDiffuseMode; - bool32 UseASGWarp; - int32 LightMapResolution; - int32 BakeMode; - int32 SolveMode; - bool32 EnableDiffuse; - bool32 EnableSpecular; - bool32 EnableDirectLighting; - bool32 EnableIndirectLighting; - bool32 EnableIndirectDiffuse; - bool32 EnableIndirectSpecular; - bool32 EnableAlbedoMaps; - bool32 EnableNormalMaps; - float NormalMapIntensity; - float DiffuseAlbedoScale; - float RoughnessScale; - float BloomExposure; - float BloomMagnitude; - float BloomBlurSigma; - bool32 ViewIndirectSpecular; - }; - - extern ConstantBuffer CBuffer; - - void Initialize(ID3D11Device* device); - void Update(); - void UpdateCBuffer(ID3D11DeviceContext* context); -}; - -// ================================================================================================ - -enum class BRDF -{ - GGX = 0, - Beckmann = 1, - Velvet = 2, - - NumValues -}; - -namespace AppSettings -{ - const uint64 CubeMapStart = uint64(SkyModes::CubeMapEnnis); - const uint64 NumCubeMaps = uint64(SkyModes::NumValues) - CubeMapStart; - - inline const wchar* CubeMapPaths(uint64 idx) - { - Assert_(idx < NumCubeMaps); - - const wchar* Paths[] = - { - L"..\\Content\\EnvMaps\\Ennis.dds", - L"..\\Content\\EnvMaps\\GraceCathedral.dds", - L"..\\Content\\EnvMaps\\Uffizi.dds", - }; - StaticAssert_(ArraySize_(Paths) == NumCubeMaps); - - return Paths[idx]; - } - - Float3 SunLuminance(); - Float3 SunIlluminance(); - - inline float ISO_() - { - static const float ISOValues[] = - { - 100.0f, 200.0f, 400.0f, 800.0f - }; - StaticAssert_(ArraySize_(ISOValues) == uint64(ISORatings::NumValues)); - - return ISOValues[uint64(AppSettings::ISORating)]; - } - - inline float ApertureFNumber_() - { - static const float FNumbers[] = - { - 1.8f, 2.0f, 2.2f, 2.5f, 2.8f, 3.2f, 3.5f, 4.0f, 4.5f, 5.0f, 5.6f, 6.3f, 7.1f, 8.0f, - 9.0f, 10.0f, 11.0f, 13.0f, 14.0f, 16.0f, 18.0f, 20.0f, 22.0f - }; - StaticAssert_(ArraySize_(FNumbers) == uint64(FStops::NumValues)); - - return FNumbers[uint64(AppSettings::ApertureSize)]; - } - - inline float ApertureWidth_() - { - return (FocalLength / ApertureFNumber_()) * 0.5f; - } - - inline float ShutterSpeedValue_() - { - static const float ShutterSpeedValues[] = - { - 1.0f / 1.0f, 1.0f / 2.0f, 1.0f / 4.0f, 1.0f / 8.0f, 1.0f / 15.0f, 1.0f / 30.0f, - 1.0f / 60.0f, 1.0f / 125.0f, 1.0f / 250.0f, 1.0f / 500.0f, 1.0f / 1000.0f, 1.0f / 2000.0f, 1.0f / 4000.0f, - }; - StaticAssert_(ArraySize_(ShutterSpeedValues) == uint64(ShutterSpeeds::NumValues)); - - return ShutterSpeedValues[uint64(AppSettings::ShutterSpeed)]; - } - - inline float VerticalFOV(float aspectRatio) - { - float verticalSize = FilmSize / aspectRatio; - return 2.0f * std::atan2(verticalSize, 2.0f * FocalLength); - } - - inline void SetFocalLengthFromVFOV(float FOV, float aspectRatio) - { - float fs = FilmSize.RawValue(); - float verticalSize = fs / aspectRatio; - FocalLength.SetValue(2.0f * (verticalSize * 0.5f) / tanf(FOV * 0.5f)); - } - - inline float BokehPolygonAmount_() - { - return std::sqrt(Saturate((ApertureFNumber_() - 1.8f) / (5.0f - 1.8f))); - } - - inline bool HasSunDirChanged() - { - return AppSettings::SunDirType.Changed() || - AppSettings::SunDirection.Changed() || - AppSettings::SunAzimuth.Changed() || - AppSettings::SunElevation.Changed(); - } - - inline void UpdateHorizontalCoords() - { - Float3 sunDir = SunDirection.Value(); - SunElevation.SetValue(RadToDeg(asin(sunDir.y))); - - float rad = atan2(sunDir.z, sunDir.x); - if(rad < 0.0f) - rad = 2.0f * Pi + rad; - - float deg = RadToDeg(rad); - SunAzimuth.SetValue(deg); - } - - inline void UpdateUnitVector() - { - Float3 newDir; - newDir.x = cos(DegToRad(SunAzimuth)) * cos(DegToRad(SunElevation)); - newDir.y = sin(DegToRad(SunElevation)); - newDir.z = sin(DegToRad(SunAzimuth)) * cos(DegToRad(SunElevation)); - SunDirection.SetValue(newDir); - } - - inline uint32 NumMSAASamples(MSAAModes mode) - { - static const uint32 NumSamples[uint32(MSAAModes::NumValues)] = { 1, 2, 4, 8 }; - return NumSamples[uint32(mode)]; - } - - inline uint32 NumMSAASamples() - { - return NumMSAASamples(MSAAMode); - } - - inline uint64 BasisCount(uint64 bakeMode) - { - Assert_(bakeMode < uint64(BakeModes::NumValues)); - static const uint64 BasisCounts[] = { 1, 3, 4, 9, 4, 6, 5, 6, 9, 12 }; - StaticAssert_(ArraySize_(BasisCounts) == uint64(BakeModes::NumValues)); - Assert_(BasisCounts[bakeMode] <= MaxBasisCount); - return BasisCounts[bakeMode]; - } - - inline uint64 BasisCount(BakeModes bakeMode) - { - return BasisCount(uint64(bakeMode)); - } - - inline uint64 BasisCount() - { - return BasisCount(uint64(BakeMode)); - } - - inline uint64 SGCount(BakeModes bakeMode) - { - Assert_(uint64(bakeMode) < uint64(BakeModes::NumValues)); - if(uint64(bakeMode) >= uint64(BakeModes::SG5)) - return BasisCount(bakeMode); - else - return 0; - } - - inline uint64 SGCount() - { - return SGCount(BakeMode); - } - - inline bool SupportsProgressiveIntegration(BakeModes bakeMode, SolveModes solveMode) - { - if(SGCount(bakeMode) > 0 && (solveMode == SolveModes::SVD || solveMode == SolveModes::NNLS)) - return false; - else - return true; - } - - void UpdateUI(); +#pragma once + +#include +#include +#include + +using namespace SampleFramework11; + +enum class SunDirectionTypes +{ + UnitVector = 0, + HorizontalCoordSystem = 1, + + NumValues +}; + +typedef EnumSettingT SunDirectionTypesSetting; + +enum class SkyModes +{ + None = 0, + Procedural = 1, + Simple = 2, + CubeMapEnnis = 3, + CubeMapGraceCathedral = 4, + CubeMapUffizi = 5, + + NumValues +}; + +typedef EnumSettingT SkyModesSetting; + +enum class LightUnits +{ + Luminance = 0, + Illuminance = 1, + LuminousPower = 2, + EV100 = 3, + + NumValues +}; + +typedef EnumSettingT LightUnitsSetting; + +enum class ExposureModes +{ + ManualSimple = 0, + Manual_SBS = 1, + Manual_SOS = 2, + Automatic = 3, + + NumValues +}; + +typedef EnumSettingT ExposureModesSetting; + +enum class FStops +{ + FStop1Point8 = 0, + FStop2Point0 = 1, + FStop2Point2 = 2, + FStop2Point5 = 3, + FStop2Point8 = 4, + FStop3Point2 = 5, + FStop3Point5 = 6, + FStop4Point0 = 7, + FStop4Point5 = 8, + FStop5Point0 = 9, + FStop5Point6 = 10, + FStop6Point3 = 11, + FStop7Point1 = 12, + FStop8Point0 = 13, + FStop9Point0 = 14, + FStop10Point0 = 15, + FStop11Point0 = 16, + FStop13Point0 = 17, + FStop14Point0 = 18, + FStop16Point0 = 19, + FStop18Point0 = 20, + FStop20Point0 = 21, + FStop22Point0 = 22, + + NumValues +}; + +typedef EnumSettingT FStopsSetting; + +enum class ISORatings +{ + ISO100 = 0, + ISO200 = 1, + ISO400 = 2, + ISO800 = 3, + + NumValues +}; + +typedef EnumSettingT ISORatingsSetting; + +enum class ShutterSpeeds +{ + ShutterSpeed1Over1 = 0, + ShutterSpeed1Over2 = 1, + ShutterSpeed1Over4 = 2, + ShutterSpeed1Over8 = 3, + ShutterSpeed1Over15 = 4, + ShutterSpeed1Over30 = 5, + ShutterSpeed1Over60 = 6, + ShutterSpeed1Over125 = 7, + ShutterSpeed1Over250 = 8, + ShutterSpeed1Over500 = 9, + ShutterSpeed1Over1000 = 10, + ShutterSpeed1Over2000 = 11, + ShutterSpeed1Over4000 = 12, + + NumValues +}; + +typedef EnumSettingT ShutterSpeedsSetting; + +enum class ToneMappingModes +{ + FilmStock = 0, + Linear = 1, + ACES = 2, + Hejl2015 = 3, + Hable = 4, + + NumValues +}; + +typedef EnumSettingT ToneMappingModesSetting; + +enum class MSAAModes +{ + MSAANone = 0, + MSAA2x = 1, + MSAA4x = 2, + MSAA8x = 3, + + NumValues +}; + +typedef EnumSettingT MSAAModesSetting; + +enum class FilterTypes +{ + Box = 0, + Triangle = 1, + Gaussian = 2, + BlackmanHarris = 3, + Smoothstep = 4, + BSpline = 5, + + NumValues +}; + +typedef EnumSettingT FilterTypesSetting; + +enum class JitterModes +{ + None = 0, + Uniform2x = 1, + Hammersley4x = 2, + Hammersley8x = 3, + Hammersley16x = 4, + + NumValues +}; + +typedef EnumSettingT JitterModesSetting; + +enum class SGDiffuseModes +{ + InnerProduct = 0, + Punctual = 1, + Fitted = 2, + + NumValues +}; + +typedef EnumSettingT SGDiffuseModesSetting; + +enum class SampleModes +{ + Random = 0, + Stratified = 1, + Hammersley = 2, + UniformGrid = 3, + CMJ = 4, + + NumValues +}; + +typedef EnumSettingT SampleModesSetting; + +enum class BakeModes +{ + Diffuse = 0, + HL2 = 1, + SH4 = 2, + SH9 = 3, + H4 = 4, + H6 = 5, + SG5 = 6, + SG6 = 7, + SG9 = 8, + SG12 = 9, + + NumValues +}; + +typedef EnumSettingT BakeModesSetting; + +enum class SolveModes +{ + Projection = 0, + SVD = 1, + NNLS = 2, + + NumValues +}; + +typedef EnumSettingT SolveModesSetting; + +enum class ProbeModes +{ + CubeMap = 0, + AmbientCube = 1, + L1_SH = 2, + L2_SH = 3, + + NumValues +}; + +typedef EnumSettingT ProbeModesSetting; + +enum class Scenes +{ + Box = 0, + WhiteRoom = 1, + Sponza = 2, + + NumValues +}; + +typedef EnumSettingT ScenesSetting; + +enum class VoxelVisualizerModes +{ + None = 0, + Geometry = 1, + RayMarch = 2, + + NumValues +}; + +typedef EnumSettingT VoxelVisualizerModesSetting; + +namespace AppSettings +{ + static const float BaseSunSize = 0.2700f; + static const int64 MaxSGCount = 12; + static const int64 MaxBasisCount = 12; + + extern BoolSetting EnableSun; + extern BoolSetting SunAreaLightApproximation; + extern ColorSetting SunTintColor; + extern FloatSetting SunIntensityScale; + extern FloatSetting SunSize; + extern BoolSetting NormalizeSunIntensity; + extern SunDirectionTypesSetting SunDirType; + extern DirectionSetting SunDirection; + extern FloatSetting SunAzimuth; + extern FloatSetting SunElevation; + extern SkyModesSetting SkyMode; + extern ColorSetting SkyColor; + extern FloatSetting Turbidity; + extern ColorSetting GroundAlbedo; + extern BoolSetting EnableAreaLight; + extern ColorSetting AreaLightColor; + extern FloatSetting AreaLightIlluminance; + extern FloatSetting AreaLightLuminousPower; + extern FloatSetting AreaLightEV100; + extern LightUnitsSetting AreaLightUnits; + extern FloatSetting AreaLightIlluminanceDistance; + extern FloatSetting AreaLightSize; + extern FloatSetting AreaLightX; + extern FloatSetting AreaLightY; + extern FloatSetting AreaLightZ; + extern FloatSetting AreaLightShadowBias; + extern BoolSetting BakeDirectAreaLight; + extern BoolSetting EnableAreaLightShadows; + extern ExposureModesSetting ExposureMode; + extern FloatSetting ManualExposure; + extern FStopsSetting ApertureSize; + extern ISORatingsSetting ISORating; + extern ShutterSpeedsSetting ShutterSpeed; + extern FloatSetting FilmSize; + extern FloatSetting FocalLength; + extern FloatSetting FocusDistance; + extern IntSetting NumBlades; + extern BoolSetting EnableDOF; + extern FloatSetting KeyValue; + extern FloatSetting AdaptationRate; + extern FloatSetting ApertureFNumber; + extern FloatSetting ApertureWidth; + extern FloatSetting ShutterSpeedValue; + extern FloatSetting ISO; + extern FloatSetting BokehPolygonAmount; + extern ToneMappingModesSetting ToneMappingMode; + extern FloatSetting WhitePoint_Hejl; + extern FloatSetting ShoulderStrength; + extern FloatSetting LinearStrength; + extern FloatSetting LinearAngle; + extern FloatSetting ToeStrength; + extern FloatSetting WhitePoint_Hable; + extern MSAAModesSetting MSAAMode; + extern FilterTypesSetting FilterType; + extern FloatSetting FilterSize; + extern FloatSetting GaussianSigma; + extern BoolSetting EnableTemporalAA; + extern JitterModesSetting JitterMode; + extern FloatSetting JitterScale; + extern SGDiffuseModesSetting SGDiffuseMode; + extern BoolSetting UseASGWarp; + extern IntSetting LightMapResolution; + extern IntSetting NumBakeSamples; + extern SampleModesSetting BakeSampleMode; + extern IntSetting MaxBakePathLength; + extern IntSetting BakeRussianRouletteDepth; + extern FloatSetting BakeRussianRouletteProbability; + extern BakeModesSetting BakeMode; + extern SolveModesSetting SolveMode; + extern BoolSetting UseProbes; + extern ProbeModesSetting ProbeMode; + extern IntSetting ProbeResX; + extern IntSetting ProbeResY; + extern IntSetting ProbeResZ; + extern IntSetting ProbeCubemapCaptureRes; + extern IntSetting ProbeIrradianceCubemapRes; + extern IntSetting ProbeDistanceCubemapRes; + extern FloatSetting SceneBoundsScale; + extern BoolSetting WeightProbesByNormal; + extern BoolSetting WeightProbesByVisibility; + extern FloatSetting DistanceFilterSharpness; + extern IntSetting ProbeIntegrationSamples; + extern IntSetting ProbeDistanceIntegrationSamples; + extern BoolSetting BakeWithVCT; + extern IntSetting VoxelResolution; + extern ScenesSetting CurrentScene; + extern BoolSetting EnableDiffuse; + extern BoolSetting EnableSpecular; + extern BoolSetting EnableDirectLighting; + extern BoolSetting EnableIndirectLighting; + extern BoolSetting EnableIndirectDiffuse; + extern BoolSetting EnableIndirectSpecular; + extern BoolSetting EnableAlbedoMaps; + extern BoolSetting EnableNormalMaps; + extern FloatSetting NormalMapIntensity; + extern FloatSetting DiffuseAlbedoScale; + extern FloatSetting RoughnessScale; + extern BoolSetting ShowGroundTruth; + extern IntSetting NumRenderSamples; + extern SampleModesSetting RenderSampleMode; + extern IntSetting MaxRenderPathLength; + extern IntSetting RenderRussianRouletteDepth; + extern FloatSetting RenderRussianRouletteProbability; + extern BoolSetting EnableRenderBounceSpecular; + extern FloatSetting BloomExposure; + extern FloatSetting BloomMagnitude; + extern FloatSetting BloomBlurSigma; + extern BoolSetting EnableLuminancePicker; + extern BoolSetting ShowBakeDataVisualizer; + extern BoolSetting ShowProbeVisualizer; + extern BoolSetting ViewIndirectDiffuse; + extern BoolSetting ViewIndirectSpecular; + extern VoxelVisualizerModesSetting VoxelVisualizerMode; + extern IntSetting VoxelVisualizerMipLevel; + extern Button SaveLightSettings; + extern Button LoadLightSettings; + extern Button SaveEXRScreenshot; + extern BoolSetting ShowSunIntensity; + extern BoolSetting AlwaysRegenerateProbes; + extern BoolSetting AlwaysRevoxelize; + extern FloatSetting SceneBoundsOffsetX; + extern FloatSetting SceneBoundsOffsetY; + extern FloatSetting SceneBoundsOffsetZ; + + struct AppSettingsCBuffer + { + bool32 EnableSun; + bool32 SunAreaLightApproximation; + Float4Align Float3 SunTintColor; + float SunIntensityScale; + float SunSize; + int32 SunDirType; + Float4Align Float3 SunDirection; + float SunAzimuth; + float SunElevation; + bool32 EnableAreaLight; + Float4Align Float3 AreaLightColor; + float AreaLightSize; + float AreaLightX; + float AreaLightY; + float AreaLightZ; + float AreaLightShadowBias; + bool32 BakeDirectAreaLight; + bool32 EnableAreaLightShadows; + int32 ExposureMode; + float ManualExposure; + float FilmSize; + float FocalLength; + float FocusDistance; + int32 NumBlades; + float KeyValue; + float AdaptationRate; + float ApertureFNumber; + float ApertureWidth; + float ShutterSpeedValue; + float ISO; + float BokehPolygonAmount; + int32 ToneMappingMode; + float WhitePoint_Hejl; + float ShoulderStrength; + float LinearStrength; + float LinearAngle; + float ToeStrength; + float WhitePoint_Hable; + int32 MSAAMode; + int32 FilterType; + float FilterSize; + float GaussianSigma; + int32 SGDiffuseMode; + bool32 UseASGWarp; + int32 LightMapResolution; + int32 BakeMode; + int32 SolveMode; + bool32 UseProbes; + int32 ProbeMode; + int32 ProbeResX; + int32 ProbeResY; + int32 ProbeResZ; + int32 ProbeCubemapCaptureRes; + int32 ProbeIrradianceCubemapRes; + int32 ProbeDistanceCubemapRes; + bool32 WeightProbesByNormal; + bool32 WeightProbesByVisibility; + float DistanceFilterSharpness; + int32 ProbeIntegrationSamples; + int32 ProbeDistanceIntegrationSamples; + bool32 BakeWithVCT; + int32 VoxelResolution; + bool32 EnableDiffuse; + bool32 EnableSpecular; + bool32 EnableDirectLighting; + bool32 EnableIndirectLighting; + bool32 EnableIndirectDiffuse; + bool32 EnableIndirectSpecular; + bool32 EnableAlbedoMaps; + bool32 EnableNormalMaps; + float NormalMapIntensity; + float DiffuseAlbedoScale; + float RoughnessScale; + float BloomExposure; + float BloomMagnitude; + float BloomBlurSigma; + bool32 ViewIndirectDiffuse; + bool32 ViewIndirectSpecular; + int32 VoxelVisualizerMipLevel; + }; + + extern ConstantBuffer CBuffer; + + void Initialize(ID3D11Device* device); + void Update(); + void UpdateCBuffer(ID3D11DeviceContext* context); +}; + +// ================================================================================================ + +enum class BRDF +{ + GGX = 0, + Beckmann = 1, + Velvet = 2, + + NumValues +}; + +namespace AppSettings +{ + const uint64 CubeMapStart = uint64(SkyModes::CubeMapEnnis); + const uint64 NumCubeMaps = uint64(SkyModes::NumValues) - CubeMapStart; + + inline const wchar* CubeMapPaths(uint64 idx) + { + Assert_(idx < NumCubeMaps); + + const wchar* Paths[] = + { + L"..\\Content\\EnvMaps\\Ennis.dds", + L"..\\Content\\EnvMaps\\GraceCathedral.dds", + L"..\\Content\\EnvMaps\\Uffizi.dds", + }; + StaticAssert_(ArraySize_(Paths) == NumCubeMaps); + + return Paths[idx]; + } + + Float3 SunLuminance(); + Float3 SunIlluminance(); + + inline float ISO_() + { + static const float ISOValues[] = + { + 100.0f, 200.0f, 400.0f, 800.0f + }; + StaticAssert_(ArraySize_(ISOValues) == uint64(ISORatings::NumValues)); + + return ISOValues[uint64(AppSettings::ISORating)]; + } + + inline float ApertureFNumber_() + { + static const float FNumbers[] = + { + 1.8f, 2.0f, 2.2f, 2.5f, 2.8f, 3.2f, 3.5f, 4.0f, 4.5f, 5.0f, 5.6f, 6.3f, 7.1f, 8.0f, + 9.0f, 10.0f, 11.0f, 13.0f, 14.0f, 16.0f, 18.0f, 20.0f, 22.0f + }; + StaticAssert_(ArraySize_(FNumbers) == uint64(FStops::NumValues)); + + return FNumbers[uint64(AppSettings::ApertureSize)]; + } + + inline float ApertureWidth_() + { + return (FocalLength / ApertureFNumber_()) * 0.5f; + } + + inline float ShutterSpeedValue_() + { + static const float ShutterSpeedValues[] = + { + 1.0f / 1.0f, 1.0f / 2.0f, 1.0f / 4.0f, 1.0f / 8.0f, 1.0f / 15.0f, 1.0f / 30.0f, + 1.0f / 60.0f, 1.0f / 125.0f, 1.0f / 250.0f, 1.0f / 500.0f, 1.0f / 1000.0f, 1.0f / 2000.0f, 1.0f / 4000.0f, + }; + StaticAssert_(ArraySize_(ShutterSpeedValues) == uint64(ShutterSpeeds::NumValues)); + + return ShutterSpeedValues[uint64(AppSettings::ShutterSpeed)]; + } + + inline float VerticalFOV(float aspectRatio) + { + float verticalSize = FilmSize / aspectRatio; + return 2.0f * std::atan2(verticalSize, 2.0f * FocalLength); + } + + inline void SetFocalLengthFromVFOV(float FOV, float aspectRatio) + { + float fs = FilmSize.RawValue(); + float verticalSize = fs / aspectRatio; + FocalLength.SetValue(2.0f * (verticalSize * 0.5f) / tanf(FOV * 0.5f)); + } + + inline float BokehPolygonAmount_() + { + return std::sqrt(Saturate((ApertureFNumber_() - 1.8f) / (5.0f - 1.8f))); + } + + inline bool HasSunDirChanged() + { + return AppSettings::SunDirType.Changed() || + AppSettings::SunDirection.Changed() || + AppSettings::SunAzimuth.Changed() || + AppSettings::SunElevation.Changed(); + } + + inline void UpdateHorizontalCoords() + { + Float3 sunDir = SunDirection.Value(); + SunElevation.SetValue(RadToDeg(asin(sunDir.y))); + + float rad = atan2(sunDir.z, sunDir.x); + if(rad < 0.0f) + rad = 2.0f * Pi + rad; + + float deg = RadToDeg(rad); + SunAzimuth.SetValue(deg); + } + + inline void UpdateUnitVector() + { + Float3 newDir; + newDir.x = cos(DegToRad(SunAzimuth)) * cos(DegToRad(SunElevation)); + newDir.y = sin(DegToRad(SunElevation)); + newDir.z = sin(DegToRad(SunAzimuth)) * cos(DegToRad(SunElevation)); + SunDirection.SetValue(newDir); + } + + inline uint32 NumMSAASamples(MSAAModes mode) + { + static const uint32 NumSamples[uint32(MSAAModes::NumValues)] = { 1, 2, 4, 8 }; + return NumSamples[uint32(mode)]; + } + + inline uint32 NumMSAASamples() + { + return NumMSAASamples(MSAAMode); + } + + inline uint64 BasisCount(uint64 bakeMode) + { + Assert_(bakeMode < uint64(BakeModes::NumValues)); + static const uint64 BasisCounts[] = { 1, 3, 4, 9, 4, 6, 5, 6, 9, 12 }; + StaticAssert_(ArraySize_(BasisCounts) == uint64(BakeModes::NumValues)); + Assert_(BasisCounts[bakeMode] <= MaxBasisCount); + return BasisCounts[bakeMode]; + } + + inline uint64 BasisCount(BakeModes bakeMode) + { + return BasisCount(uint64(bakeMode)); + } + + inline uint64 BasisCount() + { + return BasisCount(uint64(BakeMode)); + } + + inline uint64 SGCount(BakeModes bakeMode) + { + Assert_(uint64(bakeMode) < uint64(BakeModes::NumValues)); + if(uint64(bakeMode) >= uint64(BakeModes::SG5)) + return BasisCount(bakeMode); + else + return 0; + } + + inline uint64 SGCount() + { + return SGCount(BakeMode); + } + + inline bool SupportsProgressiveIntegration(BakeModes bakeMode, SolveModes solveMode) + { + if(SGCount(bakeMode) > 0 && (solveMode == SolveModes::SVD || solveMode == SolveModes::NNLS)) + return false; + else + return true; + } + + inline uint64 NumProbes() + { + return ProbeResX * ProbeResY * ProbeResZ; + } + + inline uint64 ProbeBasisCount(uint64 probeMode) + { + Assert_(probeMode < uint64(ProbeModes::NumValues)); + static const uint64 BasisCounts[] = { 1, 6, 4, 9 }; + StaticAssert_(ArraySize_(BasisCounts) == uint64(ProbeModes::NumValues)); + Assert_(BasisCounts[probeMode] <= MaxBasisCount); + return BasisCounts[probeMode]; + } + + inline uint64 ProbeBasisCount(ProbeModes probeMode) + { + return BasisCount(uint64(probeMode)); + } + + inline uint64 ProbeBasisCount() + { + return BasisCount(uint64(ProbeMode)); + } + + inline uint64 ProbeSGCount(ProbeModes probeMode) + { + /*Assert_(uint64(probeMode) < uint64(ProbeModes::NumValues)); + if(uint64(probeMode) >= uint64(ProbeModes::SG5)) + return BasisCount(probeMode); + else*/ + return 0; + } + + inline uint64 ProbeSGCount() + { + return SGCount(BakeMode); + } + + void UpdateUI(); } \ No newline at end of file diff --git a/BakingLab/AppSettings.hlsl b/BakingLab/AppSettings.hlsl index bc8a603..1beb2f5 100644 --- a/BakingLab/AppSettings.hlsl +++ b/BakingLab/AppSettings.hlsl @@ -1,185 +1,211 @@ -cbuffer AppSettings : register(b7) -{ - bool EnableSun; - bool SunAreaLightApproximation; - float3 SunTintColor; - float SunIntensityScale; - float SunSize; - int SunDirType; - float3 SunDirection; - float SunAzimuth; - float SunElevation; - bool EnableAreaLight; - float3 AreaLightColor; - float AreaLightSize; - float AreaLightX; - float AreaLightY; - float AreaLightZ; - float AreaLightShadowBias; - bool BakeDirectAreaLight; - bool EnableAreaLightShadows; - int ExposureMode; - float ManualExposure; - float FilmSize; - float FocalLength; - float FocusDistance; - int NumBlades; - float KeyValue; - float AdaptationRate; - float ApertureFNumber; - float ApertureWidth; - float ShutterSpeedValue; - float ISO; - float BokehPolygonAmount; - int ToneMappingMode; - float WhitePoint_Hejl; - float ShoulderStrength; - float LinearStrength; - float LinearAngle; - float ToeStrength; - float WhitePoint_Hable; - int MSAAMode; - int FilterType; - float FilterSize; - float GaussianSigma; - int SGDiffuseMode; - bool UseASGWarp; - int LightMapResolution; - int BakeMode; - int SolveMode; - bool EnableDiffuse; - bool EnableSpecular; - bool EnableDirectLighting; - bool EnableIndirectLighting; - bool EnableIndirectDiffuse; - bool EnableIndirectSpecular; - bool EnableAlbedoMaps; - bool EnableNormalMaps; - float NormalMapIntensity; - float DiffuseAlbedoScale; - float RoughnessScale; - float BloomExposure; - float BloomMagnitude; - float BloomBlurSigma; - bool ViewIndirectSpecular; -} - -static const int SunDirectionTypes_UnitVector = 0; -static const int SunDirectionTypes_HorizontalCoordSystem = 1; - -static const int SkyModes_None = 0; -static const int SkyModes_Procedural = 1; -static const int SkyModes_Simple = 2; -static const int SkyModes_CubeMapEnnis = 3; -static const int SkyModes_CubeMapGraceCathedral = 4; -static const int SkyModes_CubeMapUffizi = 5; - -static const int LightUnits_Luminance = 0; -static const int LightUnits_Illuminance = 1; -static const int LightUnits_LuminousPower = 2; -static const int LightUnits_EV100 = 3; - -static const int ExposureModes_ManualSimple = 0; -static const int ExposureModes_Manual_SBS = 1; -static const int ExposureModes_Manual_SOS = 2; -static const int ExposureModes_Automatic = 3; - -static const int FStops_FStop1Point8 = 0; -static const int FStops_FStop2Point0 = 1; -static const int FStops_FStop2Point2 = 2; -static const int FStops_FStop2Point5 = 3; -static const int FStops_FStop2Point8 = 4; -static const int FStops_FStop3Point2 = 5; -static const int FStops_FStop3Point5 = 6; -static const int FStops_FStop4Point0 = 7; -static const int FStops_FStop4Point5 = 8; -static const int FStops_FStop5Point0 = 9; -static const int FStops_FStop5Point6 = 10; -static const int FStops_FStop6Point3 = 11; -static const int FStops_FStop7Point1 = 12; -static const int FStops_FStop8Point0 = 13; -static const int FStops_FStop9Point0 = 14; -static const int FStops_FStop10Point0 = 15; -static const int FStops_FStop11Point0 = 16; -static const int FStops_FStop13Point0 = 17; -static const int FStops_FStop14Point0 = 18; -static const int FStops_FStop16Point0 = 19; -static const int FStops_FStop18Point0 = 20; -static const int FStops_FStop20Point0 = 21; -static const int FStops_FStop22Point0 = 22; - -static const int ISORatings_ISO100 = 0; -static const int ISORatings_ISO200 = 1; -static const int ISORatings_ISO400 = 2; -static const int ISORatings_ISO800 = 3; - -static const int ShutterSpeeds_ShutterSpeed1Over1 = 0; -static const int ShutterSpeeds_ShutterSpeed1Over2 = 1; -static const int ShutterSpeeds_ShutterSpeed1Over4 = 2; -static const int ShutterSpeeds_ShutterSpeed1Over8 = 3; -static const int ShutterSpeeds_ShutterSpeed1Over15 = 4; -static const int ShutterSpeeds_ShutterSpeed1Over30 = 5; -static const int ShutterSpeeds_ShutterSpeed1Over60 = 6; -static const int ShutterSpeeds_ShutterSpeed1Over125 = 7; -static const int ShutterSpeeds_ShutterSpeed1Over250 = 8; -static const int ShutterSpeeds_ShutterSpeed1Over500 = 9; -static const int ShutterSpeeds_ShutterSpeed1Over1000 = 10; -static const int ShutterSpeeds_ShutterSpeed1Over2000 = 11; -static const int ShutterSpeeds_ShutterSpeed1Over4000 = 12; - -static const int ToneMappingModes_FilmStock = 0; -static const int ToneMappingModes_Linear = 1; -static const int ToneMappingModes_ACES = 2; -static const int ToneMappingModes_Hejl2015 = 3; -static const int ToneMappingModes_Hable = 4; - -static const int MSAAModes_MSAANone = 0; -static const int MSAAModes_MSAA2x = 1; -static const int MSAAModes_MSAA4x = 2; -static const int MSAAModes_MSAA8x = 3; - -static const int FilterTypes_Box = 0; -static const int FilterTypes_Triangle = 1; -static const int FilterTypes_Gaussian = 2; -static const int FilterTypes_BlackmanHarris = 3; -static const int FilterTypes_Smoothstep = 4; -static const int FilterTypes_BSpline = 5; - -static const int JitterModes_None = 0; -static const int JitterModes_Uniform2x = 1; -static const int JitterModes_Hammersley4x = 2; -static const int JitterModes_Hammersley8x = 3; -static const int JitterModes_Hammersley16x = 4; - -static const int SGDiffuseModes_InnerProduct = 0; -static const int SGDiffuseModes_Punctual = 1; -static const int SGDiffuseModes_Fitted = 2; - -static const int SampleModes_Random = 0; -static const int SampleModes_Stratified = 1; -static const int SampleModes_Hammersley = 2; -static const int SampleModes_UniformGrid = 3; -static const int SampleModes_CMJ = 4; - -static const int BakeModes_Diffuse = 0; -static const int BakeModes_HL2 = 1; -static const int BakeModes_SH4 = 2; -static const int BakeModes_SH9 = 3; -static const int BakeModes_H4 = 4; -static const int BakeModes_H6 = 5; -static const int BakeModes_SG5 = 6; -static const int BakeModes_SG6 = 7; -static const int BakeModes_SG9 = 8; -static const int BakeModes_SG12 = 9; - -static const int SolveModes_Projection = 0; -static const int SolveModes_SVD = 1; -static const int SolveModes_NNLS = 2; - -static const int Scenes_Box = 0; -static const int Scenes_WhiteRoom = 1; -static const int Scenes_Sponza = 2; - -static const float BaseSunSize = 0.2700f; -static const int MaxSGCount = 12; -static const int MaxBasisCount = 12; +cbuffer AppSettings : register(b7) +{ + bool EnableSun; + bool SunAreaLightApproximation; + float3 SunTintColor; + float SunIntensityScale; + float SunSize; + int SunDirType; + float3 SunDirection; + float SunAzimuth; + float SunElevation; + bool EnableAreaLight; + float3 AreaLightColor; + float AreaLightSize; + float AreaLightX; + float AreaLightY; + float AreaLightZ; + float AreaLightShadowBias; + bool BakeDirectAreaLight; + bool EnableAreaLightShadows; + int ExposureMode; + float ManualExposure; + float FilmSize; + float FocalLength; + float FocusDistance; + int NumBlades; + float KeyValue; + float AdaptationRate; + float ApertureFNumber; + float ApertureWidth; + float ShutterSpeedValue; + float ISO; + float BokehPolygonAmount; + int ToneMappingMode; + float WhitePoint_Hejl; + float ShoulderStrength; + float LinearStrength; + float LinearAngle; + float ToeStrength; + float WhitePoint_Hable; + int MSAAMode; + int FilterType; + float FilterSize; + float GaussianSigma; + int SGDiffuseMode; + bool UseASGWarp; + int LightMapResolution; + int BakeMode; + int SolveMode; + bool UseProbes; + int ProbeMode; + int ProbeResX; + int ProbeResY; + int ProbeResZ; + int ProbeCubemapCaptureRes; + int ProbeIrradianceCubemapRes; + int ProbeDistanceCubemapRes; + bool WeightProbesByNormal; + bool WeightProbesByVisibility; + float DistanceFilterSharpness; + int ProbeIntegrationSamples; + int ProbeDistanceIntegrationSamples; + bool BakeWithVCT; + int VoxelResolution; + bool EnableDiffuse; + bool EnableSpecular; + bool EnableDirectLighting; + bool EnableIndirectLighting; + bool EnableIndirectDiffuse; + bool EnableIndirectSpecular; + bool EnableAlbedoMaps; + bool EnableNormalMaps; + float NormalMapIntensity; + float DiffuseAlbedoScale; + float RoughnessScale; + float BloomExposure; + float BloomMagnitude; + float BloomBlurSigma; + bool ViewIndirectDiffuse; + bool ViewIndirectSpecular; + int VoxelVisualizerMipLevel; +} + +static const int SunDirectionTypes_UnitVector = 0; +static const int SunDirectionTypes_HorizontalCoordSystem = 1; + +static const int SkyModes_None = 0; +static const int SkyModes_Procedural = 1; +static const int SkyModes_Simple = 2; +static const int SkyModes_CubeMapEnnis = 3; +static const int SkyModes_CubeMapGraceCathedral = 4; +static const int SkyModes_CubeMapUffizi = 5; + +static const int LightUnits_Luminance = 0; +static const int LightUnits_Illuminance = 1; +static const int LightUnits_LuminousPower = 2; +static const int LightUnits_EV100 = 3; + +static const int ExposureModes_ManualSimple = 0; +static const int ExposureModes_Manual_SBS = 1; +static const int ExposureModes_Manual_SOS = 2; +static const int ExposureModes_Automatic = 3; + +static const int FStops_FStop1Point8 = 0; +static const int FStops_FStop2Point0 = 1; +static const int FStops_FStop2Point2 = 2; +static const int FStops_FStop2Point5 = 3; +static const int FStops_FStop2Point8 = 4; +static const int FStops_FStop3Point2 = 5; +static const int FStops_FStop3Point5 = 6; +static const int FStops_FStop4Point0 = 7; +static const int FStops_FStop4Point5 = 8; +static const int FStops_FStop5Point0 = 9; +static const int FStops_FStop5Point6 = 10; +static const int FStops_FStop6Point3 = 11; +static const int FStops_FStop7Point1 = 12; +static const int FStops_FStop8Point0 = 13; +static const int FStops_FStop9Point0 = 14; +static const int FStops_FStop10Point0 = 15; +static const int FStops_FStop11Point0 = 16; +static const int FStops_FStop13Point0 = 17; +static const int FStops_FStop14Point0 = 18; +static const int FStops_FStop16Point0 = 19; +static const int FStops_FStop18Point0 = 20; +static const int FStops_FStop20Point0 = 21; +static const int FStops_FStop22Point0 = 22; + +static const int ISORatings_ISO100 = 0; +static const int ISORatings_ISO200 = 1; +static const int ISORatings_ISO400 = 2; +static const int ISORatings_ISO800 = 3; + +static const int ShutterSpeeds_ShutterSpeed1Over1 = 0; +static const int ShutterSpeeds_ShutterSpeed1Over2 = 1; +static const int ShutterSpeeds_ShutterSpeed1Over4 = 2; +static const int ShutterSpeeds_ShutterSpeed1Over8 = 3; +static const int ShutterSpeeds_ShutterSpeed1Over15 = 4; +static const int ShutterSpeeds_ShutterSpeed1Over30 = 5; +static const int ShutterSpeeds_ShutterSpeed1Over60 = 6; +static const int ShutterSpeeds_ShutterSpeed1Over125 = 7; +static const int ShutterSpeeds_ShutterSpeed1Over250 = 8; +static const int ShutterSpeeds_ShutterSpeed1Over500 = 9; +static const int ShutterSpeeds_ShutterSpeed1Over1000 = 10; +static const int ShutterSpeeds_ShutterSpeed1Over2000 = 11; +static const int ShutterSpeeds_ShutterSpeed1Over4000 = 12; + +static const int ToneMappingModes_FilmStock = 0; +static const int ToneMappingModes_Linear = 1; +static const int ToneMappingModes_ACES = 2; +static const int ToneMappingModes_Hejl2015 = 3; +static const int ToneMappingModes_Hable = 4; + +static const int MSAAModes_MSAANone = 0; +static const int MSAAModes_MSAA2x = 1; +static const int MSAAModes_MSAA4x = 2; +static const int MSAAModes_MSAA8x = 3; + +static const int FilterTypes_Box = 0; +static const int FilterTypes_Triangle = 1; +static const int FilterTypes_Gaussian = 2; +static const int FilterTypes_BlackmanHarris = 3; +static const int FilterTypes_Smoothstep = 4; +static const int FilterTypes_BSpline = 5; + +static const int JitterModes_None = 0; +static const int JitterModes_Uniform2x = 1; +static const int JitterModes_Hammersley4x = 2; +static const int JitterModes_Hammersley8x = 3; +static const int JitterModes_Hammersley16x = 4; + +static const int SGDiffuseModes_InnerProduct = 0; +static const int SGDiffuseModes_Punctual = 1; +static const int SGDiffuseModes_Fitted = 2; + +static const int SampleModes_Random = 0; +static const int SampleModes_Stratified = 1; +static const int SampleModes_Hammersley = 2; +static const int SampleModes_UniformGrid = 3; +static const int SampleModes_CMJ = 4; + +static const int BakeModes_Diffuse = 0; +static const int BakeModes_HL2 = 1; +static const int BakeModes_SH4 = 2; +static const int BakeModes_SH9 = 3; +static const int BakeModes_H4 = 4; +static const int BakeModes_H6 = 5; +static const int BakeModes_SG5 = 6; +static const int BakeModes_SG6 = 7; +static const int BakeModes_SG9 = 8; +static const int BakeModes_SG12 = 9; + +static const int SolveModes_Projection = 0; +static const int SolveModes_SVD = 1; +static const int SolveModes_NNLS = 2; + +static const int ProbeModes_CubeMap = 0; +static const int ProbeModes_AmbientCube = 1; +static const int ProbeModes_L1_SH = 2; +static const int ProbeModes_L2_SH = 3; + +static const int Scenes_Box = 0; +static const int Scenes_WhiteRoom = 1; +static const int Scenes_Sponza = 2; + +static const int VoxelVisualizerModes_None = 0; +static const int VoxelVisualizerModes_Geometry = 1; +static const int VoxelVisualizerModes_RayMarch = 2; + +static const float BaseSunSize = 0.2700f; +static const int MaxSGCount = 12; +static const int MaxBasisCount = 12; diff --git a/BakingLab/BakeDataVisualizer.hlsl b/BakingLab/BakeDataVisualizer.hlsl index 3e66ed8..d2b7d60 100644 --- a/BakingLab/BakeDataVisualizer.hlsl +++ b/BakingLab/BakeDataVisualizer.hlsl @@ -1,186 +1,188 @@ -//================================================================================================= -// -// Baking Lab -// by MJP and David Neubelt -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -//================================================================================================= -// Includes -//================================================================================================= -#include "SharedConstants.h" -#include -#include "AppSettings.hlsl" -#include "SG.hlsl" - -//================================================================================================= -// Constant buffers -//================================================================================================= -cbuffer Constants : register(b0) -{ - float4x4 ViewProjection; - float4 SGDirections[MaxSGCount]; - float SGSharpness; -} - -//================================================================================================= -// Resources -//================================================================================================= -StructuredBuffer BakePoints : register(t0); -Texture2DArray BakedLightingMap : register(t0); -SamplerState LinearSampler : register(s0); - -//================================================================================================= -// Input/Output structs -//================================================================================================= -struct VSOutput -{ - float4 PositionCS : SV_Position; - float3 NormalTS : NORMALTS; - float2 LightMapUV : LIGHTMAPUV; -}; - -struct PSInput -{ - float4 PositionSS : SV_Position; - float3 NormalTS : NORMALTS; - float2 LightMapUV : LIGHTMAPUV; -}; - -//================================================================================================= -// Vertex shader -//================================================================================================= -VSOutput VS(in float3 SpherePosition : POSITION, in uint InstanceID : SV_InstanceID) -{ - VSOutput output; - - // Get the sample point for this sphere - BakePoint bakePoint = BakePoints[InstanceID]; - - // Transform the sphere the orientation and position of the sample point - float3 bitangent = normalize(cross(bakePoint.Normal, bakePoint.Tangent)); - bitangent *= sign(dot(bitangent, bakePoint.Bitangent)); - float4x4 transform = float4x4(float4(bakePoint.Tangent, 0.0f), - float4(bitangent, 0.0f), - float4(bakePoint.Normal, 0.0f), - float4(bakePoint.Position, 1.0f)); - - float size = min(bakePoint.Size.x, bakePoint.Size.y) * 0.3f; - float3 positionWS = mul(float4(SpherePosition * size, 1.0f), transform).xyz; - output.PositionCS = mul(float4(positionWS, 1.0f), ViewProjection); - output.NormalTS = SpherePosition; - output.LightMapUV = (bakePoint.TexelPos + 0.5f) / LightMapResolution; - - return output; -} - -float3 EvalSGs(in float2 lightMapUV, in uint numSGs, in float3 dir) -{ - float3 output = 0.0f; - - [unroll] - for(uint i = 0; i < numSGs; ++i) - { - SG sg; - sg.Amplitude = BakedLightingMap.SampleLevel(LinearSampler, float3(lightMapUV, i), 0.0f).xyz; - sg.Axis = SGDirections[i].xyz; - sg.Sharpness = SGSharpness; - - output += EvaluateSG(sg, dir); - } - - return output; -} - -//================================================================================================= -// Pixel shader -//================================================================================================= -float4 PS(in PSInput input) : SV_Target0 -{ - float3 output = 0.0f; - - float3 normalTS = normalize(input.NormalTS); - float2 uv = input.LightMapUV; - - if(BakeMode == BakeModes_Diffuse) - { - output = BakedLightingMap.SampleLevel(LinearSampler, float3(uv, 0.0f), 0.0f).xyz; - } - else if(BakeMode == BakeModes_HL2) - { - const float3 BasisDirs[3] = - { - float3(-1.0f / sqrt(6.0f), -1.0f / sqrt(2.0f), 1.0f / sqrt(3.0f)), - float3(-1.0f / sqrt(6.0f), 1.0f / sqrt(2.0f), 1.0f / sqrt(3.0f)), - float3(sqrt(2.0f / 3.0f), 0.0f, 1.0f / sqrt(3.0f)), - }; - - [unroll] - for(uint i = 0; i < 3; ++i) - { - float3 lightMap = BakedLightingMap.SampleLevel(LinearSampler, float3(uv, i), 0.0f).xyz;; - output += saturate(dot(normalTS, BasisDirs[i])) * lightMap * InvPi; - } - } - else if(BakeMode == BakeModes_SH4) - { - SH4Color shRadiance; - - [unroll] - for(uint i = 0; i < 4; ++i) - shRadiance.c[i] = BakedLightingMap.SampleLevel(LinearSampler, float3(uv, i), 0.0f).xyz; - - output = EvalSH4(normalTS, shRadiance); - } - else if(BakeMode == BakeModes_SH9) - { - SH9Color shRadiance; - - [unroll] - for(uint i = 0; i < 9; ++i) - shRadiance.c[i] = BakedLightingMap.SampleLevel(LinearSampler, float3(uv, i), 0.0f).xyz; - - output = EvalSH9(normalTS, shRadiance); - } - else if(BakeMode == BakeModes_H4) - { - H4Color hbIrradiance; - - [unroll] - for(uint i = 0; i < 4; ++i) - hbIrradiance.c[i] = BakedLightingMap.SampleLevel(LinearSampler, float3(uv, i), 0.0f).xyz; - - output = EvalH4(normalTS, hbIrradiance) * InvPi; - } - else if(BakeMode == BakeModes_H6) - { - H6Color hbIrradiance; - - [unroll] - for(uint i = 0; i < 6; ++i) - hbIrradiance.c[i] = BakedLightingMap.SampleLevel(LinearSampler, float3(uv, i), 0.0f).xyz; - - output = EvalH6(normalTS, hbIrradiance) * InvPi; - } - else if(BakeMode == BakeModes_SG5) - { - output = EvalSGs(uv, 5, normalTS); - } - else if(BakeMode == BakeModes_SG6) - { - output = EvalSGs(uv, 6, normalTS); - } - else if(BakeMode == BakeModes_SG9) - { - output = EvalSGs(uv, 9, normalTS); - } - else if(BakeMode == BakeModes_SG12) - { - output = EvalSGs(uv, 12, normalTS); - } - - return float4(output, 1.0f); +//================================================================================================= +// +// Baking Lab +// by MJP and David Neubelt +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +//================================================================================================= +// Includes +//================================================================================================= +#include "SharedConstants.h" +#include +#include "AppSettings.hlsl" +#include "SG.hlsl" + +//================================================================================================= +// Constant buffers +//================================================================================================= +cbuffer Constants : register(b0) +{ + float4x4 ViewProjection; + float4 SGDirections[MaxSGCount]; + float SGSharpness; + float3 SceneMinBounds; + float3 SceneMaxBounds; +} + +//================================================================================================= +// Resources +//================================================================================================= +StructuredBuffer BakePoints : register(t0); +Texture2DArray BakedLightingMap : register(t0); +SamplerState LinearSampler : register(s0); + +//================================================================================================= +// Input/Output structs +//================================================================================================= +struct VSOutput +{ + float4 PositionCS : SV_Position; + float3 NormalTS : NORMALTS; + float2 LightMapUV : LIGHTMAPUV; +}; + +struct PSInput +{ + float4 PositionSS : SV_Position; + float3 NormalTS : NORMALTS; + float2 LightMapUV : LIGHTMAPUV; +}; + +//================================================================================================= +// Vertex shader +//================================================================================================= +VSOutput VS(in float3 SpherePosition : POSITION, in uint InstanceID : SV_InstanceID) +{ + VSOutput output; + + // Get the sample point for this sphere + BakePoint bakePoint = BakePoints[InstanceID]; + + // Transform the sphere the orientation and position of the sample point + float3 bitangent = normalize(cross(bakePoint.Normal, bakePoint.Tangent)); + bitangent *= sign(dot(bitangent, bakePoint.Bitangent)); + float4x4 transform = float4x4(float4(bakePoint.Tangent, 0.0f), + float4(bitangent, 0.0f), + float4(bakePoint.Normal, 0.0f), + float4(bakePoint.Position, 1.0f)); + + float size = min(bakePoint.Size.x, bakePoint.Size.y) * 0.3f; + float3 positionWS = mul(float4(SpherePosition * size, 1.0f), transform).xyz; + output.PositionCS = mul(float4(positionWS, 1.0f), ViewProjection); + output.NormalTS = SpherePosition; + output.LightMapUV = (bakePoint.TexelPos + 0.5f) / LightMapResolution; + + return output; +} + +float3 EvalSGs(in float2 lightMapUV, in uint numSGs, in float3 dir) +{ + float3 output = 0.0f; + + [unroll] + for(uint i = 0; i < numSGs; ++i) + { + SG sg; + sg.Amplitude = BakedLightingMap.SampleLevel(LinearSampler, float3(lightMapUV, i), 0.0f).xyz; + sg.Axis = SGDirections[i].xyz; + sg.Sharpness = SGSharpness; + + output += EvaluateSG(sg, dir); + } + + return output; +} + +//================================================================================================= +// Pixel shader +//================================================================================================= +float4 PS(in PSInput input) : SV_Target0 +{ + float3 output = 0.0f; + + float3 normalTS = normalize(input.NormalTS); + float2 uv = input.LightMapUV; + + if(BakeMode == BakeModes_Diffuse) + { + output = BakedLightingMap.SampleLevel(LinearSampler, float3(uv, 0.0f), 0.0f).xyz; + } + else if(BakeMode == BakeModes_HL2) + { + const float3 BasisDirs[3] = + { + float3(-1.0f / sqrt(6.0f), -1.0f / sqrt(2.0f), 1.0f / sqrt(3.0f)), + float3(-1.0f / sqrt(6.0f), 1.0f / sqrt(2.0f), 1.0f / sqrt(3.0f)), + float3(sqrt(2.0f / 3.0f), 0.0f, 1.0f / sqrt(3.0f)), + }; + + [unroll] + for(uint i = 0; i < 3; ++i) + { + float3 lightMap = BakedLightingMap.SampleLevel(LinearSampler, float3(uv, i), 0.0f).xyz;; + output += saturate(dot(normalTS, BasisDirs[i])) * lightMap * InvPi; + } + } + else if(BakeMode == BakeModes_SH4) + { + SH4Color shRadiance; + + [unroll] + for(uint i = 0; i < 4; ++i) + shRadiance.c[i] = BakedLightingMap.SampleLevel(LinearSampler, float3(uv, i), 0.0f).xyz; + + output = EvalSH4(normalTS, shRadiance); + } + else if(BakeMode == BakeModes_SH9) + { + SH9Color shRadiance; + + [unroll] + for(uint i = 0; i < 9; ++i) + shRadiance.c[i] = BakedLightingMap.SampleLevel(LinearSampler, float3(uv, i), 0.0f).xyz; + + output = EvalSH9(normalTS, shRadiance); + } + else if(BakeMode == BakeModes_H4) + { + H4Color hbIrradiance; + + [unroll] + for(uint i = 0; i < 4; ++i) + hbIrradiance.c[i] = BakedLightingMap.SampleLevel(LinearSampler, float3(uv, i), 0.0f).xyz; + + output = EvalH4(normalTS, hbIrradiance) * InvPi; + } + else if(BakeMode == BakeModes_H6) + { + H6Color hbIrradiance; + + [unroll] + for(uint i = 0; i < 6; ++i) + hbIrradiance.c[i] = BakedLightingMap.SampleLevel(LinearSampler, float3(uv, i), 0.0f).xyz; + + output = EvalH6(normalTS, hbIrradiance) * InvPi; + } + else if(BakeMode == BakeModes_SG5) + { + output = EvalSGs(uv, 5, normalTS); + } + else if(BakeMode == BakeModes_SG6) + { + output = EvalSGs(uv, 6, normalTS); + } + else if(BakeMode == BakeModes_SG9) + { + output = EvalSGs(uv, 9, normalTS); + } + else if(BakeMode == BakeModes_SG12) + { + output = EvalSGs(uv, 12, normalTS); + } + + return float4(output, 1.0f); } \ No newline at end of file diff --git a/BakingLab/BakingLab.cpp b/BakingLab/BakingLab.cpp index eaf6f80..0b1fda6 100644 --- a/BakingLab/BakingLab.cpp +++ b/BakingLab/BakingLab.cpp @@ -53,10 +53,16 @@ static const Float3 SceneCameraPositions[] = { Float3(0.0f, 2.5f, -15.0f), Float static const Float2 SceneCameraRotations[] = { Float2(0.0f, 0.0f), Float2(0.0f, Pi), Float2(0.414238036f, 1.39585948f) }; static const float SceneAlbedoScales[] = { 0.5f, 0.5f, 1.0f }; +static const Uint3 SceneDefaultProbeRes[] = { Uint3(4, 4, 4), Uint3(5, 3, 5), Uint3(5, 5, 5) }; +// static const float SceneDefaultBoundsScales[] = { 1.5f, 1.65f, 1.0f }; +static const float SceneDefaultBoundsScales[] = { 1.1f, 1.1f, 1.1f }; + StaticAssert_(ArraySize_(ScenePaths) >= uint64(Scenes::NumValues)); StaticAssert_(ArraySize_(SceneCameraPositions) >= uint64(Scenes::NumValues)); StaticAssert_(ArraySize_(SceneCameraRotations) >= uint64(Scenes::NumValues)); StaticAssert_(ArraySize_(SceneAlbedoScales) >= uint64(Scenes::NumValues)); +StaticAssert_(ArraySize_(SceneDefaultProbeRes) >= uint64(Scenes::NumValues)); +StaticAssert_(ArraySize_(SceneDefaultBoundsScales) >= uint64(Scenes::NumValues)); static Setting* LightSettings[] = { @@ -419,6 +425,29 @@ void BakingLab::Initialize() sceneModels[i].CreateFromMeshData(device, ScenePaths[i], true); else sceneModels[i].CreateWithAssimp(device, ScenePaths[i], true); + + // Compute the scene AABB + sceneMins[i] = FLT_MAX; + sceneMaxes[i] = -FLT_MAX; + + const uint64 numMeshes = sceneModels[i].Meshes().size(); + for(uint64 meshIdx = 0; meshIdx < numMeshes; ++meshIdx) + { + const Mesh& mesh = sceneModels[i].Meshes()[meshIdx]; + const uint8* vertices = mesh.Vertices(); + const uint64 numVertices = mesh.NumVertices(); + const uint64 stride = mesh.VertexStride(); + for(uint64 vtxIdx = 0; vtxIdx < numVertices; ++vtxIdx) + { + const Float3& vtx = *(const Float3*)(vertices + vtxIdx * stride); + sceneMins[i].x = Min(sceneMins[i].x, vtx.x); + sceneMins[i].y = Min(sceneMins[i].y, vtx.y); + sceneMins[i].z = Min(sceneMins[i].z, vtx.z); + sceneMaxes[i].x = Max(sceneMaxes[i].x, vtx.x); + sceneMaxes[i].y = Max(sceneMaxes[i].y, vtx.y); + sceneMaxes[i].z = Max(sceneMaxes[i].z, vtx.z); + } + } } Model& currentModel = sceneModels[AppSettings::CurrentScene.Value()]; @@ -444,8 +473,42 @@ void BakingLab::Initialize() backgroundVelocityVS = CompileVSFromFile(device, L"BackgroundVelocity.hlsl", "BackgroundVelocityVS"); backgroundVelocityPS = CompilePSFromFile(device, L"BackgroundVelocity.hlsl", "BackgroundVelocityPS"); + probeIntegrateIrradianceCubeMap = CompileCSFromFile(device, L"ProbeIntegrate.hlsl", "IntegrateIrradianceCubeMap"); + probeIntegrateDistanceCubeMap = CompileCSFromFile(device, L"ProbeIntegrate.hlsl", "IntegrateDistanceCubeMap"); + + probeIntegrateVolumeMap = CompileCSFromFile(device, L"ProbeIntegrate.hlsl", "IntegrateVolumeMap"); + probeIntegrateDistanceVolumeMap = CompileCSFromFile(device, L"ProbeIntegrate.hlsl", "IntegrateDistanceVolumeMap"); + + clearVoxelRadiance = CompileCSFromFile(device, L"ClearVoxelRadiance.hlsl", "ClearVoxelRadiance"); + + { + CompileOptions opts; + opts.Add("Axis_", 0); + fillVoxelHolesX = CompileCSFromFile(device, L"ClearVoxelRadiance.hlsl", "FillVoxelHoles", "cs_5_0", opts); + + opts.Reset(); + opts.Add("Axis_", 1); + fillVoxelHolesY = CompileCSFromFile(device, L"ClearVoxelRadiance.hlsl", "FillVoxelHoles", "cs_5_0", opts); + + opts.Reset(); + opts.Add("Axis_", 2); + fillVoxelHolesZ = CompileCSFromFile(device, L"ClearVoxelRadiance.hlsl", "FillVoxelHoles", "cs_5_0", opts); + } + + { + CompileOptions opts; + opts.Add("FirstMip_", 1); + generateFirstVoxelMip = CompileCSFromFile(device, L"GenerateVoxelMips.hlsl", "GenerateVoxelMips", "cs_5_0", opts); + + opts.Reset(); + opts.Add("FirstMip_", 0); + generateVoxelMips = CompileCSFromFile(device, L"GenerateVoxelMips.hlsl", "GenerateVoxelMips", "cs_5_0", opts); + } + resolveConstants.Initialize(device); backgroundVelocityConstants.Initialize(device); + integrateConstants.Initialize(device); + generateMipConstants.Initialize(device); // Init the post processor postProcessor.Initialize(device); @@ -491,7 +554,7 @@ void BakingLab::Update(const Timer& timer) if(AppSettings::SaveLightSettings) SaveLightSettings(window.GetHwnd()); - if(AppSettings::CurrentScene.Changed()) + if(AppSettings::CurrentScene.Changed() || frameCount == 0) { uint64 currSceneIdx = uint64(AppSettings::CurrentScene); meshRenderer.SetModel(&sceneModels[currSceneIdx]); @@ -499,6 +562,10 @@ void BakingLab::Update(const Timer& timer) camera.SetXRotation(SceneCameraRotations[currSceneIdx].x); camera.SetYRotation(SceneCameraRotations[currSceneIdx].y); AppSettings::DiffuseAlbedoScale.SetValue(SceneAlbedoScales[currSceneIdx]); + AppSettings::ProbeResX.SetValue(SceneDefaultProbeRes[currSceneIdx].x); + AppSettings::ProbeResY.SetValue(SceneDefaultProbeRes[currSceneIdx].y); + AppSettings::ProbeResZ.SetValue(SceneDefaultProbeRes[currSceneIdx].z); + AppSettings::SceneBoundsScale.SetValue(SceneDefaultBoundsScales[currSceneIdx]); } mouseState = MouseState::GetMouseState(window); @@ -544,8 +611,14 @@ void BakingLab::Update(const Timer& timer) camera.SetFieldOfView(AppSettings::VerticalFOV(camera.AspectRatio())); unJitteredCamera = camera; + enableTAA = AppSettings::EnableTemporalAA && + AppSettings::VoxelVisualizerMode == VoxelVisualizerModes::None && + AppSettings::ShowProbeVisualizer == false && + AppSettings::ShowBakeDataVisualizer == false && + AppSettings::ShowGroundTruth == false; + Float2 jitter = 0.0f; - if(AppSettings::EnableTemporalAA && AppSettings::EnableLuminancePicker == false && AppSettings::JitterMode != JitterModes::None) + if(enableTAA && AppSettings::EnableLuminancePicker == false && AppSettings::JitterMode != JitterModes::None) { if(AppSettings::JitterMode == JitterModes::Uniform2x) { @@ -582,18 +655,418 @@ void BakingLab::Update(const Timer& timer) if(kbState.RisingEdge(KeyboardState::V)) deviceManager.SetVSYNCEnabled(!deviceManager.VSYNCEnabled()); + Float3 sceneCenter = (sceneMaxes[AppSettings::CurrentScene] + sceneMins[AppSettings::CurrentScene]) / 2.0f;; + currSceneMin = Lerp(sceneCenter, sceneMins[AppSettings::CurrentScene], AppSettings::SceneBoundsScale); + currSceneMax = Lerp(sceneCenter, sceneMaxes[AppSettings::CurrentScene], AppSettings::SceneBoundsScale); + currSceneMin.x += AppSettings::SceneBoundsOffsetX; + currSceneMin.y += AppSettings::SceneBoundsOffsetY; + currSceneMin.z += AppSettings::SceneBoundsOffsetZ; + currSceneMax.x += AppSettings::SceneBoundsOffsetX; + currSceneMax.y += AppSettings::SceneBoundsOffsetY; + currSceneMax.z += AppSettings::SceneBoundsOffsetZ; + + if(AppSettings::ProbeMode == ProbeModes::CubeMap) + { + // Make sure that our probes fit within a single texture resource + const uint64 maxProbes = D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION / 6; + uint64 numProbes = AppSettings::NumProbes(); + if(numProbes > maxProbes) + { + const uint64 biggestDimRes = Max(Max(AppSettings::ProbeResX, AppSettings::ProbeResY), AppSettings::ProbeResZ); + const uint64 probesPerBiggestDimSlice = numProbes / biggestDimRes; + const int32 newRes = int32(maxProbes / float(probesPerBiggestDimSlice)); + if(biggestDimRes == AppSettings::ProbeResX) + AppSettings::ProbeResX.SetValue(newRes); + else if(biggestDimRes == AppSettings::ProbeResY) + AppSettings::ProbeResY.SetValue(newRes); + else + AppSettings::ProbeResZ.SetValue(newRes); + } + } + + numVoxelMips = NumMipLevels(AppSettings::VoxelResolution, AppSettings::VoxelResolution, AppSettings::VoxelResolution); + if(AppSettings::VoxelVisualizerMipLevel >= int32(numVoxelMips)) + AppSettings::VoxelVisualizerMipLevel.SetValue(numVoxelMips - 1); + meshRenderer.Update(camera, jitterOffset); } +void BakingLab::RenderProbes(MeshBakerStatus& status) +{ + PIXEvent pixEvent(L"Render Probes"); + + ID3D11DeviceContextPtr context = deviceManager.ImmediateContext(); + ID3D11DevicePtr device = deviceManager.Device(); + + const uint64 currSceneIdx = AppSettings::CurrentScene; + const uint32 numProbes = uint32(AppSettings::NumProbes()); + + if(probeCaptureMap.Width == 0 || AppSettings::ProbeCubemapCaptureRes.Changed()) + { + currProbeIdx = 0; + + const uint32 resolution = AppSettings::ProbeCubemapCaptureRes; + probeCaptureMap.Initialize(device, resolution, resolution, DXGI_FORMAT_R16G16B16A16_FLOAT, 1, 1, 0, false, false, 6, true); + probeDistanceCaptureMap.Initialize(device, resolution, resolution, DXGI_FORMAT_R16G16_UNORM, 1, 1, 0, false, false, 6, true); + probeDepthBuffer.Initialize(device, resolution, resolution, DXGI_FORMAT_D24_UNORM_S8_UINT, true); + } + + if(AppSettings::ProbeResX.Changed() || AppSettings::ProbeResY.Changed() || + AppSettings::ProbeResZ.Changed() || probeIrradianceCubeMap.ArraySize == 0 || + AppSettings::ProbeIrradianceCubemapRes.Changed() || AppSettings::ProbeDistanceCubemapRes.Changed() || + AppSettings::ProbeMode.Changed()) + { + currProbeIdx = 0; + + if(AppSettings::ProbeMode == ProbeModes::CubeMap) + { + const uint32 irrResolution = AppSettings::ProbeIrradianceCubemapRes; + const uint32 distResolution = AppSettings::ProbeDistanceCubemapRes; + probeIrradianceCubeMap.Initialize(device, irrResolution, irrResolution, DXGI_FORMAT_R16G16B16A16_FLOAT, 1, 1, 0, false, true, numProbes * 6, true); + probeDistanceCubeMap.Initialize(device, distResolution, distResolution, DXGI_FORMAT_R16G16_UNORM, 1, 1, 0, false, true, numProbes * 6, true); + } + else + { + for(uint64 i = 0; i < AppSettings::MaxBasisCount; ++i) + { + probeVolumeMaps[i].Initialize(device, AppSettings::ProbeResX, AppSettings::ProbeResY, AppSettings::ProbeResZ, + DXGI_FORMAT_R16G16B16A16_FLOAT, 1, true); + probeDistanceVolumeMaps[i].Initialize(device, AppSettings::ProbeResX, AppSettings::ProbeResY, AppSettings::ProbeResZ, + DXGI_FORMAT_R16G16_UNORM, 1, true); + } + } + } + + if(status.BakingInvalidated || AppSettings::SceneBoundsScale.Changed() || + AppSettings::AlwaysRegenerateProbes.Changed() || AppSettings::SceneBoundsOffsetX.Changed() || + AppSettings::SceneBoundsOffsetY.Changed() || AppSettings::SceneBoundsOffsetZ.Changed() || + AppSettings::DistanceFilterSharpness.Changed() || AppSettings::ProbeIntegrationSamples.Changed() || + AppSettings::ProbeDistanceIntegrationSamples.Changed()) + currProbeIdx = 0; + + if(currProbeIdx >= numProbes) + { + status.ProbeBakeProgress = 1.0f; + return; + } + + if(AppSettings::UseProbes == false) + return; + + bool32 prevUseProbes = AppSettings::UseProbes; + AppSettings::UseProbes.SetValue(false); + + uint64 probeX = currProbeIdx % AppSettings::ProbeResX; + uint64 probeY = (currProbeIdx / AppSettings::ProbeResX) % AppSettings::ProbeResY; + uint64 probeZ = currProbeIdx / (AppSettings::ProbeResX * AppSettings::ProbeResY); + + Float3 probePos; + probePos.x = Lerp(currSceneMin.x, currSceneMax.x, (probeX + 0.5f) / AppSettings::ProbeResX); + probePos.y = Lerp(currSceneMin.y, currSceneMax.y, (probeY + 0.5f) / AppSettings::ProbeResY); + probePos.z = Lerp(currSceneMin.z, currSceneMax.z, (probeZ + 0.5f) / AppSettings::ProbeResZ); + + PerspectiveCamera probeCam(1.0f, Pi_2, NearClip, FarClip); + probeCam.SetPosition(probePos); + + for(uint64 i = 0; i < 6; ++i) + { + Quaternion orientation; + if(i == 0) + orientation = Quaternion::FromAxisAngle(Float3(0.0f, 1.0f, 0.0f), Pi_2); + else if(i == 1) + orientation = Quaternion::FromAxisAngle(Float3(0.0f, 1.0f, 0.0f), -Pi_2); + else if(i == 2) + orientation = Quaternion::FromAxisAngle(Float3(1.0f, 0.0f, 0.0f), -Pi_2); + else if(i == 3) + orientation = Quaternion::FromAxisAngle(Float3(1.0f, 0.0f, 0.0f), Pi_2); + else if(i == 4) + orientation = Quaternion(); + else + orientation = Quaternion::FromAxisAngle(Float3(0.0f, 1.0f, 0.0f), Pi); + + probeCam.SetOrientation(orientation); + RenderScene(status, probeCaptureMap.RTVArraySlices[i], probeDistanceCaptureMap.RTVArraySlices[i], probeDepthBuffer, probeCam, + false, false, AppSettings::BakeDirectAreaLight, false, false, true); + } + + AppSettings::UseProbes.SetValue(prevUseProbes); + + ID3D11RenderTargetView* rtvs[2] = { }; + context->OMSetRenderTargets(2, rtvs, nullptr); + + if(AppSettings::ProbeMode == ProbeModes::CubeMap) + { + SetCSInputs(context, probeCaptureMap.SRView); + SetCSOutputs(context, probeIrradianceCubeMap.UAView); + SetCSSamplers(context, samplerStates.LinearClamp()); + SetCSShader(context, probeIntegrateIrradianceCubeMap); + + integrateConstants.Data.OutputTextureSize.x = float(probeIrradianceCubeMap.Width); + integrateConstants.Data.OutputTextureSize.y = float(probeIrradianceCubeMap.Height); + integrateConstants.Data.OutputProbeIdx = uint32(currProbeIdx); + integrateConstants.ApplyChanges(context); + integrateConstants.SetCS(context, 0); + + context->Dispatch(DispatchSize(8, probeIrradianceCubeMap.Width), DispatchSize(8, probeIrradianceCubeMap.Height), 6); + + ClearCSInputs(context); + ClearCSOutputs(context); + + SetCSInputs(context, probeDistanceCaptureMap.SRView); + SetCSOutputs(context, probeDistanceCubeMap.UAView); + SetCSShader(context, probeIntegrateDistanceCubeMap); + + integrateConstants.Data.OutputTextureSize.x = float(probeDistanceCubeMap.Width); + integrateConstants.Data.OutputTextureSize.y = float(probeDistanceCubeMap.Height); + integrateConstants.Data.OutputProbeIdx = uint32(currProbeIdx); + integrateConstants.ApplyChanges(context); + + context->Dispatch(DispatchSize(8, probeDistanceCubeMap.Width), DispatchSize(8, probeDistanceCubeMap.Height), 6); + } + else + { + SetCSInputs(context, probeCaptureMap.SRView); + SetCSSamplers(context, samplerStates.LinearClamp()); + SetCSShader(context, probeIntegrateVolumeMap); + + ID3D11UnorderedAccessView* uavs[AppSettings::MaxBasisCount] = { }; + for(uint64 i = 0; i < AppSettings::MaxBasisCount; ++i) + uavs[i] = probeVolumeMaps[i].UAView; + context->CSSetUnorderedAccessViews(0, AppSettings::MaxBasisCount, uavs, nullptr); + + integrateConstants.Data.OutputTextureSize.x = 0.0f; + integrateConstants.Data.OutputTextureSize.y = 0.0f; + integrateConstants.Data.OutputProbeIdx = uint32(currProbeIdx); + integrateConstants.ApplyChanges(context); + integrateConstants.SetCS(context, 0); + + context->Dispatch(1, 1, 1); + + ClearCSInputs(context); + ClearCSOutputs(context); + + SetCSInputs(context, probeDistanceCaptureMap.SRView); + SetCSShader(context, probeIntegrateDistanceVolumeMap); + + for(uint64 i = 0; i < AppSettings::MaxBasisCount; ++i) + uavs[i] = probeDistanceVolumeMaps[i].UAView; + context->CSSetUnorderedAccessViews(0, AppSettings::MaxBasisCount, uavs, nullptr); + + integrateConstants.Data.OutputTextureSize.x = 0.0f; + integrateConstants.Data.OutputTextureSize.y = 0.0f; + integrateConstants.Data.OutputProbeIdx = uint32(currProbeIdx); + integrateConstants.ApplyChanges(context); + + context->Dispatch(1, 1, 1); + } + + ClearCSInputs(context); + + ID3D11UnorderedAccessView* uavs[AppSettings::MaxBasisCount] = { }; + context->CSSetUnorderedAccessViews(0, AppSettings::MaxBasisCount, uavs, nullptr); + + ++currProbeIdx; + + status.ProbeBakeProgress = currProbeIdx / (numProbes - 1.0f); + + if(currProbeIdx == numProbes && AppSettings::AlwaysRegenerateProbes) + currProbeIdx = 0; +} + +void BakingLab::VoxelizeScene(MeshBakerStatus& status) +{ + ID3D11Device* device = deviceManager.Device(); + ID3D11DeviceContext* context = deviceManager.ImmediateContext(); + + bool reVoxelize = false; + + if(status.BakingInvalidated || AppSettings::AlwaysRevoxelize) + reVoxelize = true; + + if(voxelRadiance.Texture == nullptr || AppSettings::VoxelResolution.Changed()) + { + reVoxelize = true; + voxelRadiance.Initialize(device, AppSettings::VoxelResolution, AppSettings::VoxelResolution, AppSettings::VoxelResolution, + DXGI_FORMAT_R16G16B16A16_FLOAT, 1, true); + + uint32 voxelMipSize = Max(AppSettings::VoxelResolution / 2, 1u); + uint32 numMips = Max(numVoxelMips - 1, 1u); + for(uint64 i = 0; i < 6; ++i) + voxelRadianceMips[i].Initialize(device, voxelMipSize, voxelMipSize, voxelMipSize, DXGI_FORMAT_R16G16B16A16_FLOAT, numMips, true); + } + + if(reVoxelize == false) + return; + + currVoxelIdx = 0; + + PIXEvent pixEvent(L"Voxelize Scene"); + + // Clear the voxel radiance texture + SetCSShader(context, clearVoxelRadiance); + SetCSOutputs(context, voxelRadiance.UAView); + + const uint32 voxelDispatchSize = DispatchSize(4, AppSettings::VoxelResolution); + context->Dispatch(voxelDispatchSize, voxelDispatchSize, voxelDispatchSize); + + ClearCSOutputs(context); + + Float3 sceneCenter = (currSceneMin + currSceneMax) / 2.0f; + Float3 sceneHalfExtents = (currSceneMax - currSceneMin) / 2.0f; + + OrthographicCamera voxelCameraX(-sceneHalfExtents.z, -sceneHalfExtents.y, sceneHalfExtents.z, sceneHalfExtents.y, 0.0f, sceneHalfExtents.x * 2.0f); + voxelCameraX.SetPosition(Float3(currSceneMin.x, sceneCenter.y, sceneCenter.z)); + voxelCameraX.SetOrientation(Quaternion::FromAxisAngle(Float3(0.0f, 1.0f, 0.0f), Pi_2)); + + OrthographicCamera voxelCameraY(-sceneHalfExtents.x, -sceneHalfExtents.z, sceneHalfExtents.x, sceneHalfExtents.z, 0.0f, sceneHalfExtents.y * 2.0f); + voxelCameraY.SetPosition(Float3(sceneCenter.x, currSceneMin.y, sceneCenter.z)); + voxelCameraY.SetOrientation(Quaternion::FromAxisAngle(Float3(1.0f, 0.0f, 0.0f), -Pi_2)); + + OrthographicCamera voxelCameraZ(-sceneHalfExtents.x, -sceneHalfExtents.y, sceneHalfExtents.x, sceneHalfExtents.y, 0.0f, sceneHalfExtents.z * 2.0f); + voxelCameraZ.SetPosition(Float3(sceneCenter.x, sceneCenter.y, currSceneMin.z)); + + if(AppSettings::EnableSun) + meshRenderer.RenderSunShadowMap(context, voxelCameraZ, false); + + if(AppSettings::EnableAreaLight) + meshRenderer.RenderAreaLightShadowMap(context, voxelCameraZ); + + ID3D11UnorderedAccessView* uavs[] = { voxelRadiance.UAView }; + context->OMSetRenderTargetsAndUnorderedAccessViews(0, nullptr, nullptr, 0, ArraySize_(uavs), uavs, nullptr); + + for(uint64 i = 0; i < 3; ++i) + { + OrthographicCamera* voxelCamera = nullptr; + + if(i == 0) + { + voxelCamera = &voxelCameraX; + SetViewport(context, AppSettings::VoxelResolution, AppSettings::VoxelResolution); + } + else if(i == 1) + { + voxelCamera = &voxelCameraY; + SetViewport(context, AppSettings::VoxelResolution, AppSettings::VoxelResolution); + } + else if(i == 2) + { + voxelCamera = &voxelCameraZ; + SetViewport(context, AppSettings::VoxelResolution, AppSettings::VoxelResolution); + } + + meshRenderer.RenderMainPass(context, *voxelCamera, status, false, true); + } + + context->OMSetRenderTargets(0, nullptr, nullptr); + + // Fill the interioriors with opaque voxels + SetCSShader(context, fillVoxelHolesX); + SetCSOutputs(context, voxelRadiance.UAView); + + context->Dispatch(DispatchSize(8, AppSettings::VoxelResolution), DispatchSize(8, AppSettings::VoxelResolution), 1); + + SetCSShader(context, fillVoxelHolesY); + + context->Dispatch(DispatchSize(8, AppSettings::VoxelResolution), DispatchSize(8, AppSettings::VoxelResolution), 1); + + SetCSShader(context, fillVoxelHolesZ); + + context->Dispatch(DispatchSize(8, AppSettings::VoxelResolution), DispatchSize(8, AppSettings::VoxelResolution), 1); + + ClearCSOutputs(context); + + SetCSSamplers(context, samplerStates.Point()); + + const uint32 numMips = voxelRadianceMips[0].NumMipLevels; + uint32 srcMipSize = AppSettings::VoxelResolution; + for(uint32 srcMipLevel = 0; srcMipLevel < numMips; ++srcMipLevel) + { + ID3D11ShaderResourceView* srvs[6] = { }; + + if(srcMipLevel == 0) + { + SetCSShader(context, generateFirstVoxelMip); + srvs[0] = voxelRadiance.SRView; + } + else + { + SetCSShader(context, generateVoxelMips); + for(uint64 i = 0; i < 6; ++i) + srvs[i] = voxelRadianceMips[i].MipSRVs[srcMipLevel - 1]; + } + + ID3D11UnorderedAccessView* uavs[6] = { }; + for(uint64 i = 0; i < 6; ++i) + uavs[i] = voxelRadianceMips[i].MipUAVs[srcMipLevel]; + + + context->CSSetShaderResources(0, 6, srvs); + context->CSSetUnorderedAccessViews(0, 6, uavs, nullptr); + + uint32 dstMipSize = Max(srcMipSize / 2, 1u); + + generateMipConstants.Data.SrcMipTexelSize = 1.0f / srcMipSize; + generateMipConstants.Data.DstMipTexelSize = 1.0f / dstMipSize; + generateMipConstants.ApplyChanges(context); + generateMipConstants.SetCS(context, 0); + + context->Dispatch(DispatchSize(4, dstMipSize), DispatchSize(4, dstMipSize), DispatchSize(4, dstMipSize)); + + srcMipSize = dstMipSize; + + for(uint64 i = 0; i < 6; ++i) + { + srvs[i] = nullptr; + uavs[i] = nullptr; + } + + context->CSSetShaderResources(0, 6, srvs); + context->CSSetUnorderedAccessViews(0, 6, uavs, nullptr); + } +} + void BakingLab::Render(const Timer& timer) { if(AppSettings::MSAAMode.Changed()) CreateRenderTargets(); - ID3D11DeviceContextPtr context = deviceManager.ImmediateContext(); + ID3D11Device* device = deviceManager.Device(); + ID3D11DeviceContext* context = deviceManager.ImmediateContext(); MeshBakerStatus status = meshBaker.Update(unJitteredCamera, colorTargetMSAA.Width, colorTargetMSAA.Height, context, &sceneModels[AppSettings::CurrentScene]); + status.SceneMinBounds = currSceneMin; + status.SceneMaxBounds = currSceneMax; + status.SkySH = SH9Color(); + + if(AppSettings::SkyMode == SkyModes::Procedural) + { + skybox.UpdateSkyCache(device, AppSettings::SunDirection, AppSettings::GroundAlbedo, AppSettings::Turbidity); + status.SkySH = skybox.GetSkyCache().SHProjection; + } + else if(AppSettings::SkyMode == SkyModes::Simple) + { + status.SkySH = SH9Color(); + status.SkySH.Coefficients[0] = AppSettings::SkyColor.Value() * (1.0f / 0.282095f); + } + else if(AppSettings::SkyMode >= AppSettings::CubeMapStart) + { + const uint64 envMapIdx = AppSettings::SkyMode - AppSettings::CubeMapStart; + if(computedEnvMapSH[envMapIdx] == false) + { + envMapSH[envMapIdx] = ProjectCubemapToSH(device, envMaps[envMapIdx]); + computedEnvMapSH[envMapIdx] = true; + } + status.SkySH = envMapSH[envMapIdx]; + } + + VoxelizeScene(status); + + RenderProbes(status); + + status.VoxelRadiance = voxelRadiance.SRView; + for(uint64 i = 0; i < 6; ++i) + status.VoxelRadianceMips[i] = voxelRadianceMips[i].SRView; if(AppSettings::ShowGroundTruth) { @@ -614,7 +1087,18 @@ void BakingLab::Render(const Timer& timer) } else { - RenderMainPass(status); + status.ProbeIrradianceCubeMap = probeIrradianceCubeMap.SRView; + status.ProbeDistanceCubeMap = probeDistanceCubeMap.SRView; + for(uint64 i = 0; i < AppSettings::MaxBasisCount; ++i) + { + status.ProbeVolumeMaps[i] = probeVolumeMaps[i].SRView; + status.ProbeDistanceVolumeMaps[i] = probeDistanceVolumeMaps[i].SRView; + } + + RenderScene(status, colorTargetMSAA.RTView, velocityTargetMSAA.RTView, depthBuffer, camera, + AppSettings::ShowBakeDataVisualizer, AppSettings::ShowProbeVisualizer, + AppSettings::EnableAreaLight, AppSettings::VoxelVisualizerMode != VoxelVisualizerModes::None, + true, false); RenderBackgroundVelocity(); } @@ -635,71 +1119,90 @@ void BakingLab::Render(const Timer& timer) SetViewport(context, deviceManager.BackBufferWidth(), deviceManager.BackBufferHeight()); - RenderHUD(timer, status.GroundTruthProgress, status.BakeProgress, status.GroundTruthSampleCount); + RenderHUD(timer, status.GroundTruthProgress, status.BakeProgress, status.GroundTruthSampleCount, status.ProbeBakeProgress); ++frameCount; } -void BakingLab::RenderMainPass(const MeshBakerStatus& status) +void BakingLab::RenderScene(const MeshBakerStatus& status, ID3D11RenderTargetView* colorTarget, ID3D11RenderTargetView* secondRT, + const DepthStencilBuffer& depth, const Camera& cam, bool32 showBakeDataVisualizer, bool32 showProbeVisualizer, + bool32 renderAreaLight, bool32 showVoxelVisualizer, bool32 enableSkySun, bool32 probeRendering) { - PIXEvent event(L"Main Pass"); + PIXEvent event(L"Render Scene"); ID3D11DeviceContextPtr context = deviceManager.ImmediateContext(); ID3D11RenderTargetView* renderTargets[2] = { nullptr, nullptr }; - ID3D11DepthStencilView* ds = depthBuffer.DSView; - context->OMSetRenderTargets(1, renderTargets, ds); + ID3D11DepthStencilView* dsv = depth.DSView; + context->OMSetRenderTargets(1, renderTargets, dsv); - SetViewport(context, colorTargetMSAA.Width, colorTargetMSAA.Height); + SetViewport(context, depth.Width, depth.Height); - float clearColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; - context->ClearRenderTargetView(colorTargetMSAA.RTView, clearColor); - context->ClearRenderTargetView(velocityTargetMSAA.RTView, clearColor); - context->ClearDepthStencilView(ds, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 1.0f, 0); + context->ClearDepthStencilView(dsv, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 1.0f, 0); - meshRenderer.RenderDepth(context, camera, false, false); + meshRenderer.RenderDepth(context, cam, false, false); - meshRenderer.ReduceDepth(context, depthBuffer, camera); + meshRenderer.ReduceDepth(context, depth, cam); if(AppSettings::EnableSun) - meshRenderer.RenderSunShadowMap(context, camera); + meshRenderer.RenderSunShadowMap(context, cam, true); if(AppSettings::EnableAreaLight) - meshRenderer.RenderAreaLightShadowMap(context, camera); + meshRenderer.RenderAreaLightShadowMap(context, cam); - renderTargets[0] = colorTargetMSAA.RTView; - renderTargets[1] = velocityTargetMSAA.RTView; - context->OMSetRenderTargets(2, renderTargets, ds); - SetViewport(context, colorTargetMSAA.Width, colorTargetMSAA.Height); + renderTargets[0] = colorTarget; + renderTargets[1] = secondRT; + context->OMSetRenderTargets(2, renderTargets, dsv); + SetViewport(context, depth.Width, depth.Height); - meshRenderer.RenderMainPass(context, camera, status); + float maxDistance = Float3::Length(FarClip); - if(AppSettings::ShowBakeDataVisualizer) - meshRenderer.RenderBakeDataVisualizer(context, camera, status); + float clearColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + float secondClearColor[4] = { maxDistance, maxDistance * maxDistance, 0.0f, 0.0f }; + context->ClearRenderTargetView(colorTarget, clearColor); + context->ClearRenderTargetView(secondRT, secondClearColor); - if(AppSettings::EnableAreaLight) - meshRenderer.RenderAreaLight(context, camera); + if(showVoxelVisualizer) + { + context->ClearDepthStencilView(dsv, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 1.0f, 0); + } + else + { + meshRenderer.RenderMainPass(context, cam, status, probeRendering, false); + + if(showBakeDataVisualizer) + meshRenderer.RenderBakeDataVisualizer(context, cam, status); + + if(showProbeVisualizer) + meshRenderer.RenderProbeVisualizer(context, cam, status); + } + + if(renderAreaLight) + meshRenderer.RenderAreaLight(context, cam); if(AppSettings::SkyMode == SkyModes::Procedural) { - float sunSize = AppSettings::EnableSun ? AppSettings::SunSize : 0.0f; + float sunSize = (AppSettings::EnableSun && enableSkySun) ? AppSettings::SunSize : 0.0f; skybox.RenderSky(context, AppSettings::SunDirection, AppSettings::GroundAlbedo, AppSettings::SunLuminance(), sunSize, - AppSettings::Turbidity, camera.ViewMatrix(), - camera.ProjectionMatrix(), 1.0f); + AppSettings::Turbidity, cam.ViewMatrix(), + cam.ProjectionMatrix(), 1.0f); } else if(AppSettings::SkyMode == SkyModes::Simple) { - float sunSize = AppSettings::EnableSun ? AppSettings::SunSize : 0.0f; + float sunSize = (AppSettings::EnableSun && enableSkySun) ? AppSettings::SunSize : 0.0f; skybox.RenderSimpleSky(context, AppSettings::SkyColor, AppSettings::SunDirection, AppSettings::SunLuminance(), sunSize, - camera.ViewMatrix(), camera.ProjectionMatrix(), FP16Scale); + cam.ViewMatrix(), cam.ProjectionMatrix(), FP16Scale); } else if(AppSettings::SkyMode >= AppSettings::CubeMapStart) { skybox.RenderEnvironmentMap(context, envMaps[AppSettings::SkyMode - AppSettings::CubeMapStart], - camera.ViewMatrix(), camera.ProjectionMatrix(), 1.0f); + cam.ViewMatrix(), cam.ProjectionMatrix(), 1.0f); } + + if(showVoxelVisualizer) + meshRenderer.RenderVoxelVisualizer(context, cam, status); } void BakingLab::RenderAA() @@ -719,7 +1222,7 @@ void BakingLab::RenderAA() resolveConstants.Data.TextureSize = Float2(float(colorTargetMSAA.Width), float(colorTargetMSAA.Height)); resolveConstants.Data.SampleRadius = SampleRadius; - resolveConstants.Data.EnableTemporalAA = AppSettings::EnableTemporalAA && AppSettings::ShowGroundTruth == false; + resolveConstants.Data.EnableTemporalAA = enableTAA; resolveConstants.ApplyChanges(context); resolveConstants.SetPS(context, 0); @@ -796,7 +1299,7 @@ void BakingLab::RenderBackgroundVelocity() } void BakingLab::RenderHUD(const Timer& timer, float groundTruthProgress, float bakeProgress, - uint64 groundTruthSampleCount) + uint64 groundTruthSampleCount, float probeBakeProgress) { PIXEvent event(L"HUD Pass"); @@ -850,6 +1353,17 @@ void BakingLab::RenderHUD(const Timer& timer, float groundTruthProgress, float b spriteRenderer.RenderText(font, progressText.c_str(), transform); } + if(probeBakeProgress < 1.0f && AppSettings::UseProbes) + { + float percent = Round(probeBakeProgress * 10000.0f); + percent /= 100.0f; + std::wstring progressText = L"Baking probes (" + ToString(percent) + L"%)"; + + transform._41 = 35.0f; + transform._42 = deviceManager.BackBufferHeight() - 40.0f; + spriteRenderer.RenderText(font, progressText.c_str(), transform); + } + if(AppSettings::EnableLuminancePicker && mouseState.IsOverWindow) { const uint8* texels = nullptr; diff --git a/BakingLab/BakingLab.h b/BakingLab/BakingLab.h index 5ed1084..7c795bf 100644 --- a/BakingLab/BakingLab.h +++ b/BakingLab/BakingLab.h @@ -1,108 +1,161 @@ -//================================================================================================= -// -// Baking Lab -// by MJP and David Neubelt -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -#pragma once - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "PostProcessor.h" -#include "MeshRenderer.h" -#include "MeshBaker.h" - -using namespace SampleFramework11; - -class BakingLab : public App -{ - -protected: - - FirstPersonCamera camera; - - SpriteFont font; - SampleFramework11::SpriteRenderer spriteRenderer; - Skybox skybox; - ID3D11ShaderResourceViewPtr envMaps[AppSettings::NumCubeMaps]; - - PostProcessor postProcessor; - DepthStencilBuffer depthBuffer; - RenderTarget2D colorTargetMSAA; - RenderTarget2D colorResolveTarget; - RenderTarget2D prevFrameTarget; - RenderTarget2D velocityTargetMSAA; - StagingTexture2D readbackTexture; - - // Model - Model sceneModels[uint64(Scenes::NumValues)]; - MeshRenderer meshRenderer; - MeshBaker meshBaker; - - MouseState mouseState; - - float GTSampleRateBuffer[64]; - uint64 GTSampleRateBufferIdx = 0; - - VertexShaderPtr resolveVS; - PixelShaderPtr resolvePS[uint64(MSAAModes::NumValues)]; - - VertexShaderPtr backgroundVelocityVS; - PixelShaderPtr backgroundVelocityPS; - Float4x4 prevViewProjection; - - Float2 jitterOffset; - Float2 prevJitter; - uint64 frameCount = 0; - FirstPersonCamera unJitteredCamera; - - struct ResolveConstants - { - uint32 SampleRadius; - bool32 EnableTemporalAA; - Float2 TextureSize; - }; - - struct BackgroundVelocityConstants - { - Float4x4 InvViewProjection; - Float4x4 PrevViewProjection; - Float2 RTSize; - Float2 JitterOffset; - }; - - ConstantBuffer resolveConstants; - ConstantBuffer backgroundVelocityConstants; - - virtual void Initialize() override; - virtual void Render(const Timer& timer) override; - virtual void Update(const Timer& timer) override; - virtual void BeforeReset() override; - virtual void AfterReset() override; - - void CreateRenderTargets(); - - void RenderMainPass(const MeshBakerStatus& status); - void RenderAA(); - void RenderBackgroundVelocity(); - void RenderHUD(const Timer& timer, float groundTruthProgress, float bakeProgress, - uint64 groundTruthSampleCount); - -public: - - BakingLab(); -}; +//================================================================================================= +// +// Baking Lab +// by MJP and David Neubelt +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "PostProcessor.h" +#include "MeshRenderer.h" +#include "MeshBaker.h" + +using namespace SampleFramework11; + +class BakingLab : public App +{ + +protected: + + FirstPersonCamera camera; + + SpriteFont font; + SampleFramework11::SpriteRenderer spriteRenderer; + Skybox skybox; + ID3D11ShaderResourceViewPtr envMaps[AppSettings::NumCubeMaps]; + SH9Color envMapSH[AppSettings::NumCubeMaps]; + bool32 computedEnvMapSH[AppSettings::NumCubeMaps] = { }; + + PostProcessor postProcessor; + DepthStencilBuffer depthBuffer; + RenderTarget2D colorTargetMSAA; + RenderTarget2D colorResolveTarget; + RenderTarget2D prevFrameTarget; + RenderTarget2D velocityTargetMSAA; + StagingTexture2D readbackTexture; + + // Model + Model sceneModels[uint64(Scenes::NumValues)]; + Float3 sceneMins[uint64(Scenes::NumValues)]; + Float3 sceneMaxes[uint64(Scenes::NumValues)]; + Float3 currSceneMin; + Float3 currSceneMax; + MeshRenderer meshRenderer; + MeshBaker meshBaker; + + MouseState mouseState; + + float GTSampleRateBuffer[64]; + uint64 GTSampleRateBufferIdx = 0; + + VertexShaderPtr resolveVS; + PixelShaderPtr resolvePS[uint64(MSAAModes::NumValues)]; + + VertexShaderPtr backgroundVelocityVS; + PixelShaderPtr backgroundVelocityPS; + Float4x4 prevViewProjection; + + Float2 jitterOffset; + Float2 prevJitter; + uint64 frameCount = 0; + FirstPersonCamera unJitteredCamera; + bool enableTAA = false; + + RenderTarget2D probeCaptureMap; + RenderTarget2D probeDistanceCaptureMap; + RenderTarget2D probeIrradianceCubeMap; + RenderTarget2D probeDistanceCubeMap; + DepthStencilBuffer probeDepthBuffer; + + RenderTarget3D probeVolumeMaps[AppSettings::MaxBasisCount]; + RenderTarget3D probeDistanceVolumeMaps[AppSettings::MaxBasisCount]; + + uint64 currProbeIdx = 0; + + ComputeShaderPtr probeIntegrateIrradianceCubeMap; + ComputeShaderPtr probeIntegrateDistanceCubeMap; + + ComputeShaderPtr probeIntegrateVolumeMap; + ComputeShaderPtr probeIntegrateDistanceVolumeMap; + + RenderTarget3D voxelRadiance; + RenderTarget3D voxelRadianceMips[6]; + ComputeShaderPtr clearVoxelRadiance; + ComputeShaderPtr fillVoxelHolesX; + ComputeShaderPtr fillVoxelHolesY; + ComputeShaderPtr fillVoxelHolesZ; + ComputeShaderPtr generateFirstVoxelMip; + ComputeShaderPtr generateVoxelMips; + uint64 currVoxelIdx = 0; + uint32 numVoxelMips = 0; + + struct ResolveConstants + { + uint32 SampleRadius; + bool32 EnableTemporalAA; + Float2 TextureSize; + }; + + struct BackgroundVelocityConstants + { + Float4x4 InvViewProjection; + Float4x4 PrevViewProjection; + Float2 RTSize; + Float2 JitterOffset; + }; + + struct IntegrateConstants + { + Float2 OutputTextureSize; + uint32 OutputProbeIdx; + }; + + struct GenerateMipConstants + { + float SrcMipTexelSize; + float DstMipTexelSize; + }; + + ConstantBuffer resolveConstants; + ConstantBuffer backgroundVelocityConstants; + ConstantBuffer integrateConstants; + ConstantBuffer generateMipConstants; + + virtual void Initialize() override; + virtual void Render(const Timer& timer) override; + virtual void Update(const Timer& timer) override; + virtual void BeforeReset() override; + virtual void AfterReset() override; + + void CreateRenderTargets(); + + void RenderProbes(MeshBakerStatus& status); + void VoxelizeScene(MeshBakerStatus& status); + void RenderScene(const MeshBakerStatus& status, ID3D11RenderTargetView* colorTarget, ID3D11RenderTargetView* secondRT, + const DepthStencilBuffer& depth, const Camera& cam, bool32 showBakeDataVisualizer, bool32 showProbeVisualizer, + bool32 renderAreaLight, bool32 showVoxelVisualizer, bool32 enableSkySun, bool32 probeRendering); + void RenderAA(); + void RenderBackgroundVelocity(); + void RenderHUD(const Timer& timer, float groundTruthProgress, float bakeProgress, + uint64 groundTruthSampleCount, float probeBakeProgress); + +public: + + BakingLab(); +}; diff --git a/BakingLab/BakingLab.vcxproj b/BakingLab/BakingLab.vcxproj index 23d6f28..b4d2cbd 100644 --- a/BakingLab/BakingLab.vcxproj +++ b/BakingLab/BakingLab.vcxproj @@ -1,256 +1,256 @@ - - - - - Debug - x64 - - - Release - x64 - - - - {1D9C887B-E727-438B-8977-A0E7363B1FC6} - SampleTest - Win32Proj - BakingLab - 8.1 - - - - Application - Unicode - true - v140 - - - Application - Unicode - v140 - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30128.1 - $(SolutionDir)$(Configuration)\$(Platform)\ - $(Configuration)\$(Platform)\ - true - $(SolutionDir)$(Configuration)\$(Platform)\ - $(Configuration)\$(Platform)\ - false - AllRules.ruleset - - - AllRules.ruleset - - - $(IncludePath) - $(IncludePath) - $(LibraryPath) - $(LibraryPath) - - - $(ExecutablePath) - - - - Disabled - Debug_;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) - EnableFastChecks - MultiThreadedDebugDLL - Use - PCH.h - ProgramDatabase - $(IntDir)$(TargetName).pch - Fast - - - true - Windows - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - - - - - MaxSpeed - true - Release_;WIN32;NDEBUG;_WINDOWS;_ITERATOR_DEBUG_LEVEL=0;%(PreprocessorDefinitions) - MultiThreadedDLL - true - Use - ProgramDatabase - PCH.h - Fast - - - true - Windows - true - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - $(ProjectDir)\SettingsCompiler.exe %(FullPath) - Compiling settings and generating C++ code - false - $(ProjectDir)\%(Filename).deps - $(ProjectDir)\SettingsCompiler.exe %(FullPath) - Compiling settings and generating C++ code - $(ProjectDir)\%(Filename).deps - false - - - Document - - - Document - - - Document - - - Document - - - Document - - - Document - - - - - - - - - false - false - Document - - - false - false - Document - - - false - false - Document - - - false - false - Document - - - - - + + + + + Debug + x64 + + + Release + x64 + + + + {1D9C887B-E727-438B-8977-A0E7363B1FC6} + SampleTest + Win32Proj + BakingLab + 10.0.16299.0 + + + + Application + Unicode + true + v140 + + + Application + Unicode + v140 + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + $(SolutionDir)$(Configuration)\$(Platform)\ + $(Configuration)\$(Platform)\ + true + $(SolutionDir)$(Configuration)\$(Platform)\ + $(Configuration)\$(Platform)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + $(IncludePath) + $(IncludePath) + $(LibraryPath) + $(LibraryPath) + + + $(ExecutablePath) + + + + Disabled + Debug_;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Use + PCH.h + ProgramDatabase + $(IntDir)$(TargetName).pch + Fast + + + true + Windows + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + MaxSpeed + true + Release_;WIN32;NDEBUG;_WINDOWS;_ITERATOR_DEBUG_LEVEL=0;%(PreprocessorDefinitions) + MultiThreadedDLL + true + Use + ProgramDatabase + PCH.h + Fast + + + true + Windows + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $(ProjectDir)\SettingsCompiler.exe %(FullPath) + Compiling settings and generating C++ code + false + $(ProjectDir)\%(Filename).deps + $(ProjectDir)\SettingsCompiler.exe %(FullPath) + Compiling settings and generating C++ code + $(ProjectDir)\%(Filename).deps + false + + + Document + + + Document + + + Document + + + Document + + + Document + + + Document + + + + + + + + + false + false + Document + + + false + false + Document + + + false + false + Document + + + false + false + Document + + + + + \ No newline at end of file diff --git a/BakingLab/BakingLab_2013.sln b/BakingLab/BakingLab_2017.sln similarity index 89% rename from BakingLab/BakingLab_2013.sln rename to BakingLab/BakingLab_2017.sln index d0c4a63..8acb085 100644 --- a/BakingLab/BakingLab_2013.sln +++ b/BakingLab/BakingLab_2017.sln @@ -1,9 +1,8 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.31101.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BakingLab_2013", "BakingLab_2013.vcxproj", "{1D9C887B-E727-438B-8977-A0E7363B1FC6}" +# Visual Studio 15 +VisualStudioVersion = 15.0.26403.0 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BakingLab", "BakingLab_2017.vcxproj", "{1D9C887B-E727-438B-8977-A0E7363B1FC6}" ProjectSection(ProjectDependencies) = postProject {A01DD775-61A4-42F1-9B2A-772E50456A68} = {A01DD775-61A4-42F1-9B2A-772E50456A68} {C61F717F-FF92-4D36-930E-1F49C198CBEE} = {C61F717F-FF92-4D36-930E-1F49C198CBEE} diff --git a/BakingLab/BakingLab_2013.vcxproj b/BakingLab/BakingLab_2017.vcxproj similarity index 96% rename from BakingLab/BakingLab_2013.vcxproj rename to BakingLab/BakingLab_2017.vcxproj index dc9c761..051e7b8 100644 --- a/BakingLab/BakingLab_2013.vcxproj +++ b/BakingLab/BakingLab_2017.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -14,31 +14,31 @@ {1D9C887B-E727-438B-8977-A0E7363B1FC6} SampleTest Win32Proj - BakingLab_2013 - 8.1 + BakingLab + 10.0.16299.0 Application Unicode true - v120 + v141 Application Unicode - v120 + v141 - + - + @@ -101,6 +101,10 @@ + + NotUsing + NotUsing + diff --git a/BakingLab/BakingLab_2013.vcxproj.filters b/BakingLab/BakingLab_2017.vcxproj.filters similarity index 97% rename from BakingLab/BakingLab_2013.vcxproj.filters rename to BakingLab/BakingLab_2017.vcxproj.filters index 3338e3e..bf031a8 100644 --- a/BakingLab/BakingLab_2013.vcxproj.filters +++ b/BakingLab/BakingLab_2017.vcxproj.filters @@ -104,6 +104,9 @@ + + SampleFramework11\HosekSky + @@ -248,6 +251,9 @@ {f554bad2-3017-4de6-b296-a8d625a6d4df} + + {4ebf61e9-489b-46af-b8f9-8eea2eec87a2} + diff --git a/BakingLab/ClearVoxelRadiance.hlsl b/BakingLab/ClearVoxelRadiance.hlsl new file mode 100644 index 0000000..bcd541a --- /dev/null +++ b/BakingLab/ClearVoxelRadiance.hlsl @@ -0,0 +1,95 @@ +//================================================================================================= +// +// Baking Lab +// by MJP and David Neubelt +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +#include "AppSettings.hlsl" + +RWTexture3D VoxelRadiance; + +[numthreads(4, 4, 4)] +void ClearVoxelRadiance(in uint3 voxelCoord : SV_DispatchThreadID) +{ + VoxelRadiance[voxelCoord] = 0.0f; +} + +[numthreads(8, 8, 1)] +void FillVoxelHoles(in uint2 planeCoord : SV_DispatchThreadID) +{ + #if Axis_ == 0 + uint3 voxelCoord = uint3(0, planeCoord.x, planeCoord.y); + const uint3 marchDir = uint3(1, 0, 0); + const uint voxelsToMarch = VoxelResolution; + #elif Axis_ == 1 + uint3 voxelCoord = uint3(planeCoord.x, 0, planeCoord.y); + const uint3 marchDir = uint3(0, 1, 0); + const uint voxelsToMarch = VoxelResolution; + #else + uint3 voxelCoord = uint3(planeCoord.x, planeCoord.y, 0); + const uint3 marchDir = uint3(0, 0, 1); + const uint voxelsToMarch = VoxelResolution; + #endif + + bool inside = false; + + for(uint v = 0; v < voxelsToMarch; ++v) + { + float4 voxelSample = VoxelRadiance[voxelCoord]; + + if(voxelSample.w > 0.0f) + { + inside = !inside; + voxelSample.w = saturate(voxelSample.w); + } + else + { + voxelSample.xyz = 0.0f; + voxelSample.w += inside ? -1.0f : 0.0f; + } + + VoxelRadiance[voxelCoord] = voxelSample; + voxelCoord += marchDir; + } + + if(inside) + { + voxelCoord -= marchDir; + for(uint i = 0; i < voxelsToMarch; ++i) + { + float4 voxelSample = VoxelRadiance[voxelCoord]; + if(voxelSample.w > 0.0f) + break; + else + voxelSample = 0.0f; + + VoxelRadiance[voxelCoord] = voxelSample; + voxelCoord -= marchDir; + } + } + + #if Axis_ == 2 + voxelCoord = uint3(planeCoord.x, planeCoord.y, 0); + for(uint i = 0; i < voxelsToMarch; ++i) + { + float4 voxelSample = VoxelRadiance[voxelCoord]; + if(voxelSample.w < 0.0f) + { + voxelSample = 0.0f; + + if(voxelSample.w == -3.0) + { + // voxelSample.xyz = float3(0, 10.0f, 0.0f); + voxelSample.w = 1.0f; + } + + VoxelRadiance[voxelCoord] = voxelSample; + } + voxelCoord += marchDir; + } + #endif +} \ No newline at end of file diff --git a/BakingLab/DepthReduction.hlsl b/BakingLab/DepthReduction.hlsl index 7a05e3e..6c7ad00 100644 --- a/BakingLab/DepthReduction.hlsl +++ b/BakingLab/DepthReduction.hlsl @@ -1,149 +1,149 @@ -//================================================================================================= -// -// Baking Lab -// by MJP and David Neubelt -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -//================================================================================================= -// Includes -//================================================================================================= -#include "SharedConstants.h" - -//================================================================================================= -// Constants -//================================================================================================= -static const uint NumThreads = ReductionTGSize * ReductionTGSize; - -//================================================================================================= -// Resources -//================================================================================================= -#if MSAA_ - Texture2DMS DepthMap : register(t0); -#else - Texture2D DepthMap : register(t0); -#endif - -Texture2D ReductionMap : register(t0); - -RWTexture2D OutputMap : register(u0); - -cbuffer ReductionConstants : register(b0) -{ - float4x4 Projection; - float NearClip; - float FarClip; - uint2 TextureSize; - uint NumSamples; -} - -// -- shared memory -groupshared float2 depthsamples[NumThreads]; - -//================================================================================================= -// Depth reduction, intial pass -//================================================================================================= -[numthreads(ReductionTGSize, ReductionTGSize, 1)] -void DepthReductionInitialCS(in uint3 GroupID : SV_GroupID, - in uint3 GroupThreadID : SV_GroupThreadID, - uint ThreadIndex : SV_GroupIndex) -{ - float minDepth = 1.0f; - float maxDepth = 0.0f; - - uint2 samplePos = GroupID.xy * ReductionTGSize + GroupThreadID.xy; - samplePos = min(samplePos, TextureSize - 1); - - #if MSAA_ - for(uint sIdx = 0; sIdx < NumSamples; ++sIdx) - { - float depthSample = DepthMap.Load(samplePos, sIdx); - - if(depthSample < 1.0f) - { - // Convert to linear Z - depthSample = Projection._43 / (depthSample - Projection._33); - depthSample = saturate((depthSample - NearClip) / (FarClip - NearClip)); - minDepth = min(minDepth, depthSample); - maxDepth = max(maxDepth, depthSample); - } - } - #else - float depthSample = DepthMap[samplePos]; - - if(depthSample < 1.0f) - { - // Convert to linear Z - depthSample = Projection._43 / (depthSample - Projection._33); - depthSample = saturate((depthSample - NearClip) / (FarClip - NearClip)); - minDepth = min(minDepth, depthSample); - maxDepth = max(maxDepth, depthSample); - } - #endif - - // Store in shared memory - depthsamples[ThreadIndex] = float2(minDepth, maxDepth); - GroupMemoryBarrierWithGroupSync(); - - // Reduce - [unroll] - for(uint s = NumThreads / 2; s > 0; s >>= 1) - { - if(ThreadIndex < s) - { - depthsamples[ThreadIndex].x = min(depthsamples[ThreadIndex].x, depthsamples[ThreadIndex + s].x); - depthsamples[ThreadIndex].y = max(depthsamples[ThreadIndex].y, depthsamples[ThreadIndex + s].y); - } - - GroupMemoryBarrierWithGroupSync(); - } - - if(ThreadIndex == 0) - { - minDepth = depthsamples[0].x; - maxDepth = depthsamples[0].y; - OutputMap[GroupID.xy] = float2(minDepth, maxDepth); - } -} - -//================================================================================================= -// Depth reduction, 2nd pass onwards -//================================================================================================= -[numthreads(ReductionTGSize, ReductionTGSize, 1)] -void DepthReductionCS(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : SV_GroupThreadID, - in uint ThreadIndex : SV_GroupIndex) -{ - uint2 samplePos = GroupID.xy * ReductionTGSize + GroupThreadID.xy; - samplePos = min(samplePos, TextureSize - 1); - - float minDepth = ReductionMap[samplePos].x; - float maxDepth = ReductionMap[samplePos].y; - - - // Store in shared memory - depthsamples[ThreadIndex] = float2(minDepth, maxDepth); - GroupMemoryBarrierWithGroupSync(); - - // Reduce - [unroll] - for(uint s = NumThreads / 2; s > 0; s >>= 1) - { - if(ThreadIndex < s) - { - depthsamples[ThreadIndex].x = min(depthsamples[ThreadIndex].x, depthsamples[ThreadIndex + s].x); - depthsamples[ThreadIndex].y = max(depthsamples[ThreadIndex].y, depthsamples[ThreadIndex + s].y); - } - - GroupMemoryBarrierWithGroupSync(); - } - - if(ThreadIndex == 0) - { - minDepth = depthsamples[0].x; - maxDepth = depthsamples[0].y; - OutputMap[GroupID.xy] = float2(minDepth, maxDepth); - } +//================================================================================================= +// +// Baking Lab +// by MJP and David Neubelt +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +//================================================================================================= +// Includes +//================================================================================================= +#include "SharedConstants.h" + +//================================================================================================= +// Constants +//================================================================================================= +static const uint NumThreads = ReductionTGSize * ReductionTGSize; + +//================================================================================================= +// Resources +//================================================================================================= +#if MSAA_ + Texture2DMS DepthMap : register(t0); +#else + Texture2D DepthMap : register(t0); +#endif + +Texture2D ReductionMap : register(t0); + +RWTexture2D OutputMap : register(u0); + +cbuffer ReductionConstants : register(b0) +{ + float4x4 Projection; + float NearClip; + float FarClip; + uint2 TextureSize; + uint NumSamples; +} + +// -- shared memory +groupshared float2 depthsamples[NumThreads]; + +//================================================================================================= +// Depth reduction, intial pass +//================================================================================================= +[numthreads(ReductionTGSize, ReductionTGSize, 1)] +void DepthReductionInitialCS(in uint3 GroupID : SV_GroupID, + in uint3 GroupThreadID : SV_GroupThreadID, + uint ThreadIndex : SV_GroupIndex) +{ + float minDepth = 1.0f; + float maxDepth = 0.0f; + + uint2 samplePos = GroupID.xy * ReductionTGSize + GroupThreadID.xy; + samplePos = min(samplePos, TextureSize - 1); + + #if MSAA_ + for(uint sIdx = 0; sIdx < NumSamples; ++sIdx) + { + float depthSample = DepthMap.Load(samplePos, sIdx); + + if(depthSample < 1.0f) + { + // Convert to linear Z + depthSample = Projection._43 / (depthSample - Projection._33); + depthSample = saturate((depthSample - NearClip) / (FarClip - NearClip)); + minDepth = min(minDepth, depthSample); + maxDepth = max(maxDepth, depthSample); + } + } + #else + float depthSample = DepthMap[samplePos]; + + if(depthSample < 1.0f) + { + // Convert to linear Z + depthSample = Projection._43 / (depthSample - Projection._33); + depthSample = saturate((depthSample - NearClip) / (FarClip - NearClip)); + minDepth = min(minDepth, depthSample); + maxDepth = max(maxDepth, depthSample); + } + #endif + + // Store in shared memory + depthsamples[ThreadIndex] = float2(minDepth, maxDepth); + GroupMemoryBarrierWithGroupSync(); + + // Reduce + [unroll] + for(uint s = NumThreads / 2; s > 0; s >>= 1) + { + if(ThreadIndex < s) + { + depthsamples[ThreadIndex].x = min(depthsamples[ThreadIndex].x, depthsamples[ThreadIndex + s].x); + depthsamples[ThreadIndex].y = max(depthsamples[ThreadIndex].y, depthsamples[ThreadIndex + s].y); + } + + GroupMemoryBarrierWithGroupSync(); + } + + if(ThreadIndex == 0) + { + minDepth = depthsamples[0].x; + maxDepth = depthsamples[0].y; + OutputMap[GroupID.xy] = float2(minDepth, maxDepth); + } +} + +//================================================================================================= +// Depth reduction, 2nd pass onwards +//================================================================================================= +[numthreads(ReductionTGSize, ReductionTGSize, 1)] +void DepthReductionCS(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : SV_GroupThreadID, + in uint ThreadIndex : SV_GroupIndex) +{ + uint2 samplePos = GroupID.xy * ReductionTGSize + GroupThreadID.xy; + samplePos = min(samplePos, TextureSize - 1); + + float minDepth = ReductionMap[samplePos].x; + float maxDepth = ReductionMap[samplePos].y; + + + // Store in shared memory + depthsamples[ThreadIndex] = float2(minDepth, maxDepth); + GroupMemoryBarrierWithGroupSync(); + + // Reduce + [unroll] + for(uint s = NumThreads / 2; s > 0; s >>= 1) + { + if(ThreadIndex < s) + { + depthsamples[ThreadIndex].x = min(depthsamples[ThreadIndex].x, depthsamples[ThreadIndex + s].x); + depthsamples[ThreadIndex].y = max(depthsamples[ThreadIndex].y, depthsamples[ThreadIndex + s].y); + } + + GroupMemoryBarrierWithGroupSync(); + } + + if(ThreadIndex == 0) + { + minDepth = depthsamples[0].x; + maxDepth = depthsamples[0].y; + OutputMap[GroupID.xy] = float2(minDepth, maxDepth); + } } \ No newline at end of file diff --git a/BakingLab/GenerateVoxelMips.hlsl b/BakingLab/GenerateVoxelMips.hlsl new file mode 100644 index 0000000..e5dd534 --- /dev/null +++ b/BakingLab/GenerateVoxelMips.hlsl @@ -0,0 +1,170 @@ +//================================================================================================= +// +// Baking Lab +// by MJP and David Neubelt +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +cbuffer GenerateMipConstants : register(b0) +{ + float SrcMipTexelSize; + float DstMipTexelSize; +} + +Texture3D SourceMips[6] : register(t0); +RWTexture3D DestinationMips[6] : register(u0); +SamplerState PointClamp : register(s0); + + +[numthreads(4, 4, 4)] +void GenerateVoxelMips(in uint3 voxelCoord : SV_DispatchThreadID) +{ + float3 uvw = (voxelCoord + 0.5f) * DstMipTexelSize; + + static const uint3 sampleIndices[6][8] = + { + { + // +X + uint3(1, 0, 0), + uint3(0, 0, 0), + uint3(1, 1, 0), + uint3(0, 1, 0), + uint3(1, 0, 1), + uint3(0, 0, 1), + uint3(1, 1, 1), + uint3(0, 1, 1), + }, + + { + // -X + uint3(0, 0, 0), + uint3(1, 0, 0), + uint3(0, 1, 0), + uint3(1, 1, 0), + uint3(0, 0, 1), + uint3(1, 0, 1), + uint3(0, 1, 1), + uint3(1, 1, 1), + }, + + { + // +Y + uint3(0, 1, 0), + uint3(0, 0, 0), + uint3(1, 1, 0), + uint3(1, 0, 0), + uint3(0, 1, 1), + uint3(0, 0, 1), + uint3(1, 1, 1), + uint3(1, 0, 1), + }, + + { + // -Y + uint3(0, 0, 0), + uint3(0, 1, 0), + uint3(1, 0, 0), + uint3(1, 1, 0), + uint3(0, 0, 1), + uint3(0, 1, 1), + uint3(1, 0, 1), + uint3(1, 1, 1), + }, + + { + // +Z + uint3(0, 0, 1), + uint3(0, 0, 0), + uint3(0, 1, 1), + uint3(0, 1, 0), + uint3(1, 0, 1), + uint3(1, 0, 0), + uint3(1, 1, 1), + uint3(1, 1, 0), + }, + + { + // -Z + uint3(0, 0, 0), + uint3(0, 0, 1), + uint3(0, 1, 0), + uint3(0, 1, 1), + uint3(1, 0, 0), + uint3(1, 0, 1), + uint3(1, 1, 0), + uint3(1, 1, 1), + }, + }; + + [unroll] + for(uint face = 0; face < 6; ++face) + { + float4 samples[2][2][2]; + float4 sum = 0.0f; + + [unroll] + for(int z = 0; z < 2; ++z) + { + [unroll] + for(int y = 0; y < 2; ++y) + { + [unroll] + for(int x = 0; x < 2; ++x) + { + float3 offset = float3(x, y, z) - 0.5f; + offset *= SrcMipTexelSize; + + #if FirstMip_ + const uint srcTexIdx = 0; + #else + const uint srcTexIdx = face; + #endif + + samples[x][y][z] = SourceMips[srcTexIdx].SampleLevel(PointClamp, uvw + offset, 0.0f); + + sum += samples[x][y][z]; + } + } + } + + uint3 idx0 = sampleIndices[face][0]; + uint3 idx1 = sampleIndices[face][1]; + uint3 idx2 = sampleIndices[face][2]; + uint3 idx3 = sampleIndices[face][3]; + uint3 idx4 = sampleIndices[face][4]; + uint3 idx5 = sampleIndices[face][5]; + uint3 idx6 = sampleIndices[face][6]; + uint3 idx7 = sampleIndices[face][7]; + + float4 sample0 = samples[idx0.x][idx0.y][idx0.z]; + float4 sample1 = samples[idx1.x][idx1.y][idx1.z]; + float4 sample01 = float4(sample0.xyz * sample0.w + sample1.xyz * (1.0f - sample0.w), + sample0.w + sample1.w * (1.0f - sample0.w)); + + float4 sample2 = samples[idx2.x][idx2.y][idx2.z]; + float4 sample3 = samples[idx3.x][idx3.y][idx3.z]; + float4 sample23 = float4(sample2.xyz * sample2.w + sample3.xyz * (1.0f - sample2.w), + sample2.w + sample3.w * (1.0f - sample2.w)); + + float4 sample0123 = (sample01 + sample23) * 0.5f; + + float4 sample4 = samples[idx4.x][idx4.y][idx4.z]; + float4 sample5 = samples[idx5.x][idx5.y][idx5.z]; + float4 sample45 = float4(sample4.xyz * sample4.w + sample5.xyz * (1.0f - sample4.w), + sample4.w + sample5.w * (1.0f - sample4.w)); + + float4 sample6 = samples[idx6.x][idx6.y][idx6.z]; + float4 sample7 = samples[idx7.x][idx7.y][idx7.z]; + float4 sample67 = float4(sample6.xyz * sample6.w + sample7.xyz * (1.0f - sample6.w), + sample6.w + sample7.w * (1.0f - sample6.w)); + + float4 sample4567 = (sample45 + sample67) * 0.5f; + + DestinationMips[face][voxelCoord] = (sample0123 + sample4567) * 0.5f; + + // DestinationMips[face][voxelCoord] = sum / 8.0f; + } +} diff --git a/BakingLab/Mesh.hlsl b/BakingLab/Mesh.hlsl index 34c0719..b4d3a76 100644 --- a/BakingLab/Mesh.hlsl +++ b/BakingLab/Mesh.hlsl @@ -1,563 +1,1005 @@ -//================================================================================================= -// -// Baking Lab -// by MJP and David Neubelt -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -//================================================================================================= -// Includes -//================================================================================================= -#include -#include "EVSM.hlsl" -#include -#include "AppSettings.hlsl" -#include "SG.hlsl" - -//================================================================================================= -// Constants -//================================================================================================= -static const uint NumCascades = 4; - -//================================================================================================= -// Constant buffers -//================================================================================================= -cbuffer VSConstants : register(b0) -{ - float4x4 World; - float4x4 View; - float4x4 WorldViewProjection; - float4x4 PrevWorldViewProjection; -} - -cbuffer PSConstants : register(b0) -{ - float3 SunDirectionWS; - float CosSunAngularRadius; - float3 SunIlluminance; - float SinSunAngularRadius; - float3 CameraPosWS; - float4x4 ShadowMatrix; - float4 CascadeSplits; - float4 CascadeOffsets[NumCascades]; - float4 CascadeScales[NumCascades]; - float OffsetScale; - float PositiveExponent; - float NegativeExponent; - float LightBleedingReduction; - float2 RTSize; - float2 JitterOffset; - float4 SGDirections[MaxSGCount]; - float SGSharpness; -} - -//================================================================================================= -// Resources -//================================================================================================= -Texture2D AlbedoMap : register(t0); -Texture2D NormalMap : register(t1); -Texture2D RoughnessMap : register(t2); -Texture2D MetallicMap : register(t3); -Texture2DArray SunShadowMap : register(t4); -Texture2DArray BakedLightingMap : register(t5); -TextureCube AreaLightShadowMap : register(t6); -Texture3D SHSpecularLookupA : register(t7); -Texture3D SHSpecularLookupB : register(t8); - -SamplerState AnisoSampler : register(s0); -SamplerState EVSMSampler : register(s1); -SamplerState LinearSampler : register(s2); -SamplerComparisonState PCFSampler : register(s3); - -//================================================================================================= -// Input/Output structs -//================================================================================================= -struct VSInput -{ - float3 PositionOS : POSITION; - float3 NormalOS : NORMAL; - float2 TexCoord : TEXCOORD0; - float2 LightMapUV : TEXCOORD1; - float3 TangentOS : TANGENT; - float3 BitangentOS : BITANGENT; -}; - -struct VSOutput -{ - float4 PositionCS : SV_Position; - - float3 NormalWS : NORMALWS; - float3 PositionWS : POSITIONWS; - float DepthVS : DEPTHVS; - float3 TangentWS : TANGENTWS; - float3 BitangentWS : BITANGENTWS; - float2 TexCoord : TEXCOORD; - float2 LightMapUV : LIGHTMAPUV; - float3 PrevPosition : PREVPOSITION; -}; - -struct PSInput -{ - float4 PositionSS : SV_Position; - - float3 NormalWS : NORMALWS; - float3 PositionWS : POSITIONWS; - float DepthVS : DEPTHVS; - float3 TangentWS : TANGENTWS; - float3 BitangentWS : BITANGENTWS; - float2 TexCoord : TEXCOORD; - float2 LightMapUV : LIGHTMAPUV; - float3 PrevPosition : PREVPOSITION; -}; - -struct PSOutput -{ - float4 Lighting : SV_Target0; - float2 Velocity : SV_Target1; -}; - -//================================================================================================= -// Vertex Shader -//================================================================================================= -VSOutput VS(in VSInput input, in uint VertexID : SV_VertexID) -{ - VSOutput output; - - float3 positionOS = input.PositionOS; - - // Calc the world-space position - output.PositionWS = mul(float4(positionOS, 1.0f), World).xyz; - - // Calc the clip-space position - output.PositionCS = mul(float4(positionOS, 1.0f), WorldViewProjection); - output.DepthVS = output.PositionCS.w; - - - // Rotate the normal into world space - output.NormalWS = normalize(mul(input.NormalOS, (float3x3)World)); - - // Rotate the rest of the tangent frame into world space - output.TangentWS = normalize(mul(input.TangentOS, (float3x3)World)); - output.BitangentWS = normalize(mul(input.BitangentOS, (float3x3)World)); - - // Pass along the texture coordinates - output.TexCoord = input.TexCoord; - output.LightMapUV = input.LightMapUV; - - output.PrevPosition = mul(float4(input.PositionOS, 1.0f), PrevWorldViewProjection).xyw; - - return output; -} - -//------------------------------------------------------------------------------------------------- -// Samples the EVSM shadow map -//------------------------------------------------------------------------------------------------- -float SampleShadowMapEVSM(in float3 shadowPos, in float3 shadowPosDX, - in float3 shadowPosDY, uint cascadeIdx) -{ - float2 exponents = GetEVSMExponents(PositiveExponent, NegativeExponent, - CascadeScales[cascadeIdx].xyz); - float2 warpedDepth = WarpDepth(shadowPos.z, exponents); - - float4 occluder = SunShadowMap.SampleGrad(EVSMSampler, float3(shadowPos.xy, cascadeIdx), - shadowPosDX.xy, shadowPosDY.xy); - - // Derivative of warping at depth - float2 depthScale = 0.0001f * exponents * warpedDepth; - float2 minVariance = depthScale * depthScale; - - float posContrib = ChebyshevUpperBound(occluder.xz, warpedDepth.x, minVariance.x, LightBleedingReduction); - float negContrib = ChebyshevUpperBound(occluder.yw, warpedDepth.y, minVariance.y, LightBleedingReduction); - float shadowContrib = posContrib; - shadowContrib = min(shadowContrib, negContrib); - - return shadowContrib; -} - -//------------------------------------------------------------------------------------------------- -// Samples the appropriate shadow map cascade -//------------------------------------------------------------------------------------------------- -float3 SampleShadowCascade(in float3 shadowPosition, in float3 shadowPosDX, - in float3 shadowPosDY, in uint cascadeIdx) -{ - shadowPosition += CascadeOffsets[cascadeIdx].xyz; - shadowPosition *= CascadeScales[cascadeIdx].xyz; - - shadowPosDX *= CascadeScales[cascadeIdx].xyz; - shadowPosDY *= CascadeScales[cascadeIdx].xyz; - - float3 cascadeColor = 1.0f; - - float shadow = SampleShadowMapEVSM(shadowPosition, shadowPosDX, shadowPosDY, cascadeIdx); - - return shadow * cascadeColor; -} - -//-------------------------------------------------------------------------------------- -// Computes the sun visibility term by performing the shadow test -//-------------------------------------------------------------------------------------- -float3 SunShadowVisibility(in float3 positionWS, in float depthVS) -{ - float3 shadowVisibility = 1.0f; - uint cascadeIdx = 0; - - // Project into shadow space - float3 samplePos = positionWS; - float3 shadowPosition = mul(float4(samplePos, 1.0f), ShadowMatrix).xyz; - float3 shadowPosDX = ddx(shadowPosition); - float3 shadowPosDY = ddy(shadowPosition); - - // Figure out which cascade to sample from - [unroll] - for(uint i = 0; i < NumCascades - 1; ++i) - { - [flatten] - if(depthVS > CascadeSplits[i]) - cascadeIdx = i + 1; - } - - shadowVisibility = SampleShadowCascade(shadowPosition, shadowPosDX, shadowPosDY, - cascadeIdx); - - return shadowVisibility; -} - -//------------------------------------------------------------------------------------------------- -// Computes the area light shadow visibility term -//------------------------------------------------------------------------------------------------- -float AreaLightShadowVisibility(in float3 positionWS) -{ - float3 shadowPos = positionWS - float3(AreaLightX, AreaLightY, AreaLightZ); - float3 shadowDistance = length(shadowPos); - float3 shadowDir = normalize(shadowPos); - - // Doing the max of the components tells us 2 things: which cubemap face we're going to use, - // and also what the projected distance is onto the major axis for that face. - float projectedDistance = max(max(abs(shadowPos.x), abs(shadowPos.y)), abs(shadowPos.z)); - - // Compute the project depth value that matches what would be stored in the depth buffer - // for the current cube map face. Note that we use a reversed infinite projection. - float nearClip = AreaLightSize; - float a = 0.0f; - float b = nearClip; - float z = projectedDistance * a + b; - float dbDistance = z / projectedDistance; - - return AreaLightShadowMap.SampleCmpLevelZero(PCFSampler, shadowDir, dbDistance + AreaLightShadowBias); -} - -//------------------------------------------------------------------------------------------------- -// Calculates the lighting result for an analytical light source -//------------------------------------------------------------------------------------------------- -float3 CalcLighting(in float3 normal, in float3 lightDir, in float3 lightColor, - in float3 diffuseAlbedo, in float3 specularAlbedo, in float roughness, - in float3 positionWS, inout float3 irradiance) -{ - float3 lighting = diffuseAlbedo * (1.0f / 3.14159f); - - float3 view = normalize(CameraPosWS - positionWS); - const float nDotL = saturate(dot(normal, lightDir)); - if(nDotL > 0.0f) - { - const float nDotV = saturate(dot(normal, view)); - float3 h = normalize(view + lightDir); - - float3 fresnel = Fresnel(specularAlbedo, h, lightDir); - - float specular = GGX_Specular(roughness, normal, h, view, lightDir); - lighting += specular * fresnel; - } - - irradiance += nDotL * lightColor; - return lighting * nDotL * lightColor; -} - -// ------------------------------------------------------------------------------------------------ -// Computes the irradiance for an SG light source using the selected approximation -// ------------------------------------------------------------------------------------------------ -float3 SGIrradiance(in SG lightingLobe, in float3 normal, in int diffuseMode) -{ - if(diffuseMode == SGDiffuseModes_Punctual) - return SGIrradiancePunctual(lightingLobe, normal); - else if(diffuseMode == SGDiffuseModes_Fitted) - return SGIrradianceFitted(lightingLobe, normal); - else - return SGIrradianceInnerProduct(lightingLobe, normal); -} - -// ------------------------------------------------------------------------------------------------ -// Computes the specular contribution from an SG light source -// ------------------------------------------------------------------------------------------------ -float3 SpecularTermSG(in SG light, in float3 normal, in float roughness, - in float3 view, in float3 specAlbedo) -{ - if(UseASGWarp) - return SpecularTermASGWarp(light, normal, roughness, view, specAlbedo); - else - return SpecularTermSGWarp(light, normal, roughness, view, specAlbedo); -} - -// ------------------------------------------------------------------------------------------------ -// Determine the exit radiance towards the eye from the SG's stored in the lightmap -// ------------------------------------------------------------------------------------------------ -void ComputeSGContribution(in Texture2DArray bakedLightingMap, in float2 lightMapUV, in float3 normalTS, - in float3 specularAlbedo, in float roughness, in float3 viewTS, in uint numSGs, - out float3 irradiance, out float3 specular) -{ - irradiance = 0.0f; - specular = 0.0f; - - for(uint i = 0; i < numSGs; ++i) - { - SG sg; - sg.Amplitude = bakedLightingMap.SampleLevel(LinearSampler, float3(lightMapUV, i), 0.0f).xyz; - sg.Axis = SGDirections[i].xyz; - sg.Sharpness = SGSharpness; - - irradiance += SGIrradiance(sg, normalTS, SGDiffuseMode); - specular += SpecularTermSG(sg, normalTS, roughness, viewTS, specularAlbedo); - } -} - -SH9Color GetSHSpecularBRDF(in float3 viewTS, in float3x3 tangentToWorld, in float3 normalTS, - in float3 specularAlbedo, in float sqrtRoughness) -{ - // Make a local coordinate frame in tangent space, with the x-axis - // aligned with the view direction and the z-axis aligned with the normal - float3 zBasis = normalTS; - float3 yBasis = normalize(cross(zBasis, viewTS)); - float3 xBasis = normalize(cross(yBasis, zBasis)); - float3x3 localFrame = float3x3(xBasis, yBasis, zBasis); - float viewAngle = saturate(dot(normalTS, viewTS)); - - // Look up coefficients from the SH lookup texture to make the SH BRDF - SH9Color shBrdf = (SH9Color)0.0f; - - [unroll] - for(uint i = 0; i < 3; ++i) - { - float4 t0 = SHSpecularLookupA.SampleLevel(LinearSampler, float3(viewAngle, sqrtRoughness, specularAlbedo[i]), 0.0f); - float2 t1 = SHSpecularLookupB.SampleLevel(LinearSampler, float3(viewAngle, sqrtRoughness, specularAlbedo[i]), 0.0f); - shBrdf.c[0][i] = t0.x; - shBrdf.c[2][i] = t0.y; - shBrdf.c[3][i] = t0.z; - shBrdf.c[6][i] = t0.w; - shBrdf.c[7][i] = t1.x; - shBrdf.c[8][i] = t1.y; - } - - // Transform the SH BRDF to tangent space - return RotateSH9(shBrdf, localFrame); -} - -//================================================================================================= -// Pixel Shader -//================================================================================================= -PSOutput PS(in PSInput input) -{ - float3 vtxNormal = normalize(input.NormalWS); - float3 positionWS = input.PositionWS; - - float3 viewWS = normalize(CameraPosWS - positionWS); - - float3 normalWS = vtxNormal; - - float2 uv = input.TexCoord; - - float3 normalTS = float3(0, 0, 1); - float3 tangentWS = normalize(input.TangentWS); - float3 bitangentWS = normalize(input.BitangentWS); - float3x3 tangentToWorld = float3x3(tangentWS, bitangentWS, normalWS); - - if(EnableNormalMaps) - { - // Sample the normal map, and convert the normal to world space - normalTS.xy = NormalMap.Sample(AnisoSampler, uv).xy * 2.0f - 1.0f; - normalTS.z = sqrt(1.0f - saturate(normalTS.x * normalTS.x + normalTS.y * normalTS.y)); - normalTS = lerp(float3(0, 0, 1), normalTS, NormalMapIntensity); - normalWS = normalize(mul(normalTS, tangentToWorld)); - } - - float3 viewTS = mul(viewWS, transpose(tangentToWorld)); - - // Gather material parameters - float3 albedoMap = 1.0f; - - if(EnableAlbedoMaps) - albedoMap = AlbedoMap.Sample(AnisoSampler, uv).xyz; - - float metallic = saturate(MetallicMap.Sample(AnisoSampler, uv)); - float3 diffuseAlbedo = lerp(albedoMap.xyz, 0.0f, metallic) * DiffuseAlbedoScale * EnableDiffuse; - float3 specularAlbedo = lerp(0.03f, albedoMap.xyz, metallic) * EnableSpecular; - - float sqrtRoughness = RoughnessMap.Sample(AnisoSampler, uv); - sqrtRoughness *= RoughnessScale; - float roughness = sqrtRoughness * sqrtRoughness; - - float depthVS = input.DepthVS; - - // Add in the primary directional light - float3 lighting = 0.0f; - float3 irradiance = 0.0f; - - if(EnableDirectLighting && EnableSun) - { - float3 sunIrradiance = 0.0f; - float3 sunShadowVisibility = SunShadowVisibility(positionWS, depthVS); - float3 sunDirection = SunDirectionWS; - if(SunAreaLightApproximation) - { - float3 D = SunDirectionWS; - float3 R = reflect(-viewWS, normalWS); - float r = SinSunAngularRadius; - float d = CosSunAngularRadius; - float3 DDotR = dot(D, R); - float3 S = R - DDotR * D; - sunDirection = DDotR < d ? normalize(d * D + normalize(S) * r) : R; - } - lighting += CalcLighting(normalWS, sunDirection, SunIlluminance, diffuseAlbedo, specularAlbedo, - roughness, positionWS, sunIrradiance) * sunShadowVisibility; - irradiance += sunIrradiance * sunShadowVisibility; - } - - if(EnableDirectLighting && EnableAreaLight && BakeDirectAreaLight == false) - { - float3 areaLightPos = float3(AreaLightX, AreaLightY, AreaLightZ); - float3 areaLightDir = normalize(areaLightPos - positionWS); - float areaLightDist = length(areaLightPos - positionWS); - SG lightLobe = MakeSphereSG(areaLightDir, AreaLightSize, AreaLightColor * FP16Scale, areaLightDist); - float3 sgIrradiance = SGIrradiance(lightLobe, normalWS, SGDiffuseMode); - - float areaLightVisibility = 1.0f; - if(EnableAreaLightShadows) - areaLightVisibility = AreaLightShadowVisibility(positionWS); - - lighting += sgIrradiance * (diffuseAlbedo / Pi) * areaLightVisibility; - lighting += SpecularTermSG(lightLobe, normalWS, roughness, viewWS, specularAlbedo) * areaLightVisibility; - irradiance += sgIrradiance * areaLightVisibility; - } - - // Add in the indirect - if(EnableIndirectLighting || ViewIndirectSpecular) - { - float3 indirectIrradiance = 0.0f; - float3 indirectSpecular = 0.0f; - - if(BakeMode == BakeModes_Diffuse) - { - indirectIrradiance = BakedLightingMap.SampleLevel(LinearSampler, float3(input.LightMapUV, 0.0f), 0.0f).xyz * Pi; - } - else if(BakeMode == BakeModes_HL2) - { - const float3 BasisDirs[3] = - { - float3(-1.0f / sqrt(6.0f), -1.0f / sqrt(2.0f), 1.0f / sqrt(3.0f)), - float3(-1.0f / sqrt(6.0f), 1.0f / sqrt(2.0f), 1.0f / sqrt(3.0f)), - float3(sqrt(2.0f / 3.0f), 0.0f, 1.0f / sqrt(3.0f)), - }; - - float weightSum = 0.0f; - - [unroll] - for(uint i = 0; i < 3; ++i) - { - float3 lightMap = BakedLightingMap.SampleLevel(LinearSampler, float3(input.LightMapUV, i), 0.0f).xyz; - indirectIrradiance += saturate(dot(normalTS, BasisDirs[i])) * lightMap; - } - } - else if(BakeMode == BakeModes_SH4) - { - SH4Color shRadiance; - - [unroll] - for(uint i = 0; i < 4; ++i) - shRadiance.c[i] = BakedLightingMap.SampleLevel(LinearSampler, float3(input.LightMapUV, i), 0.0f).xyz; - - indirectIrradiance = EvalSH4Irradiance(normalTS, shRadiance); - - SH4Color shSpecularBRDF = ConvertToSH4(GetSHSpecularBRDF(viewTS, tangentToWorld, normalTS, specularAlbedo, sqrtRoughness)); - indirectSpecular = SHDotProduct(shSpecularBRDF, shRadiance); - } - else if(BakeMode == BakeModes_SH9) - { - SH9Color shRadiance; - - [unroll] - for(uint i = 0; i < 9; ++i) - shRadiance.c[i] = BakedLightingMap.SampleLevel(LinearSampler, float3(input.LightMapUV, i), 0.0f).xyz; - - indirectIrradiance = EvalSH9Irradiance(normalTS, shRadiance); - - SH9Color shSpecularBRDF = GetSHSpecularBRDF(viewTS, tangentToWorld, normalTS, specularAlbedo, sqrtRoughness); - indirectSpecular = SHDotProduct(shSpecularBRDF, shRadiance); - } - else if(BakeMode == BakeModes_H4) - { - H4Color hbIrradiance; - - [unroll] - for(uint i = 0; i < 4; ++i) - hbIrradiance.c[i] = BakedLightingMap.SampleLevel(LinearSampler, float3(input.LightMapUV, i), 0.0f).xyz; - - indirectIrradiance = EvalH4(normalTS, hbIrradiance); - } - else if(BakeMode == BakeModes_H6) - { - H6Color hbIrradiance; - - [unroll] - for(uint i = 0; i < 6; ++i) - hbIrradiance.c[i] = BakedLightingMap.SampleLevel(LinearSampler, float3(input.LightMapUV, i), 0.0f).xyz; - - indirectIrradiance = EvalH6(normalTS, hbIrradiance); - } - else if(BakeMode == BakeModes_SG5) - { - ComputeSGContribution(BakedLightingMap, input.LightMapUV, normalTS, specularAlbedo, roughness, - viewTS, 5, indirectIrradiance, indirectSpecular); - } - else if(BakeMode == BakeModes_SG6) - { - ComputeSGContribution(BakedLightingMap, input.LightMapUV, normalTS, specularAlbedo, roughness, - viewTS, 6, indirectIrradiance, indirectSpecular); - } - else if(BakeMode == BakeModes_SG9) - { - ComputeSGContribution(BakedLightingMap, input.LightMapUV, normalTS, specularAlbedo, roughness, - viewTS, 9, indirectIrradiance, indirectSpecular); - } - else if(BakeMode == BakeModes_SG12) - { - ComputeSGContribution(BakedLightingMap, input.LightMapUV, normalTS, specularAlbedo, roughness, - viewTS, 12, indirectIrradiance, indirectSpecular); - } - - if(EnableIndirectDiffuse) - { - irradiance += indirectIrradiance; - lighting += indirectIrradiance * (diffuseAlbedo / Pi); - } - - if(EnableIndirectSpecular) - lighting += indirectSpecular; - - if(ViewIndirectSpecular) - lighting = indirectSpecular; - } - - float illuminance = dot(irradiance, float3(0.2126f, 0.7152f, 0.0722f)); - - PSOutput output; - output.Lighting = clamp(float4(lighting, illuminance), 0.0f, FP16Max); - - float2 prevPositionSS = (input.PrevPosition.xy / input.PrevPosition.z) * float2(0.5f, -0.5f) + 0.5f; - prevPositionSS *= RTSize; - output.Velocity = input.PositionSS.xy - prevPositionSS; - output.Velocity -= JitterOffset; - output.Velocity /= RTSize; - - return output; -} +//================================================================================================= +// +// Baking Lab +// by MJP and David Neubelt +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +//================================================================================================= +// Includes +//================================================================================================= +#include +#include "EVSM.hlsl" +#include +#include "AppSettings.hlsl" +#include "SG.hlsl" + +//================================================================================================= +// Constants +//================================================================================================= +static const uint NumCascades = 4; + +//================================================================================================= +// Constant buffers +//================================================================================================= +cbuffer VSConstants : register(b0) +{ + float4x4 World; + float4x4 View; + float4x4 WorldViewProjection; + float4x4 PrevWorldViewProjection; +} + +cbuffer PSConstants : register(b1) +{ + float3 SunDirectionWS; + float CosSunAngularRadius; + float3 SunIlluminance; + float SinSunAngularRadius; + float3 CameraPosWS; + float4x4 ShadowMatrix; + float4 CascadeSplits; + float4 CascadeOffsets[NumCascades]; + float4 CascadeScales[NumCascades]; + float OffsetScale; + float PositiveExponent; + float NegativeExponent; + float LightBleedingReduction; + float2 RTSize; + float2 JitterOffset; + float4 SGDirections[MaxSGCount]; + float SGSharpness; + float3 SceneMinBounds; + float3 SceneMaxBounds; + SH9Color SkySH; +} + +//================================================================================================= +// Resources +//================================================================================================= +Texture2D AlbedoMap : register(t0); +Texture2D NormalMap : register(t1); +Texture2D RoughnessMap : register(t2); +Texture2D MetallicMap : register(t3); +Texture2DArray SunShadowMap : register(t4); +Texture2DArray BakedLightingMap : register(t5); +TextureCube AreaLightShadowMap : register(t6); +Texture3D SHSpecularLookupA : register(t7); +Texture3D SHSpecularLookupB : register(t8); +TextureCubeArray ProbeIrradianceCubeMaps : register(t9); +TextureCubeArray ProbeDistanceCubeMaps : register(t10); +Texture3D VoxelRadiance : register(t11); +Texture3D VoxelRadianceMips[6] : register(t12); +Texture3D ProbeVolumeMaps[MaxBasisCount]; +Texture3D ProbeDistanceVolumeMaps[MaxBasisCount]; + +SamplerState AnisoSampler : register(s0); +SamplerState EVSMSampler : register(s1); +SamplerState LinearSampler : register(s2); +SamplerComparisonState PCFSampler : register(s3); +SamplerState PointSampler : register(s4); +SamplerState LinearBorderSampler : register(s4); + +#if Voxelize_ + RasterizerOrderedTexture3D VoxelRadianceOutput : register(u0); +#endif + +//================================================================================================= +// Input/Output structs +//================================================================================================= +struct VSInput +{ + float3 PositionOS : POSITION; + float3 NormalOS : NORMAL; + float2 TexCoord : TEXCOORD0; + float2 LightMapUV : TEXCOORD1; + float3 TangentOS : TANGENT; + float3 BitangentOS : BITANGENT; +}; + +struct VSOutput +{ + float4 PositionCS : SV_Position; + + float3 NormalWS : NORMALWS; + float3 PositionWS : POSITIONWS; + float DepthVS : DEPTHVS; + float3 TangentWS : TANGENTWS; + float3 BitangentWS : BITANGENTWS; + float2 TexCoord : TEXCOORD; + float2 LightMapUV : LIGHTMAPUV; + float3 PrevPosition : PREVPOSITION; +}; + +struct PSInput +{ + float4 PositionSS : SV_Position; + + float3 NormalWS : NORMALWS; + float3 PositionWS : POSITIONWS; + float DepthVS : DEPTHVS; + float3 TangentWS : TANGENTWS; + float3 BitangentWS : BITANGENTWS; + float2 TexCoord : TEXCOORD; + float2 LightMapUV : LIGHTMAPUV; + float3 PrevPosition : PREVPOSITION; +}; + +#if Voxelize_ + #define PSOutput void +#else + struct PSOutput + { + float4 Lighting : SV_Target0; + #if ProbeRendering_ + float2 ProbeDistance : SV_Target1; + #else + float2 Velocity : SV_Target1; + #endif + }; +#endif + +//================================================================================================= +// Vertex Shader +//================================================================================================= +VSOutput VS(in VSInput input, in uint VertexID : SV_VertexID) +{ + VSOutput output; + + float3 positionOS = input.PositionOS; + + // Calc the world-space position + output.PositionWS = mul(float4(positionOS, 1.0f), World).xyz; + + // Calc the clip-space position + output.PositionCS = mul(float4(positionOS, 1.0f), WorldViewProjection); + + #if Voxelize_ + output.DepthVS = output.PositionWS.z - SceneMinBounds.z; + #else + output.DepthVS = output.PositionCS.w; + #endif + + // Rotate the normal into world space + output.NormalWS = normalize(mul(input.NormalOS, (float3x3)World)); + + // Rotate the rest of the tangent frame into world space + output.TangentWS = normalize(mul(input.TangentOS, (float3x3)World)); + output.BitangentWS = normalize(mul(input.BitangentOS, (float3x3)World)); + + // Pass along the texture coordinates + output.TexCoord = input.TexCoord; + output.LightMapUV = input.LightMapUV; + + output.PrevPosition = mul(float4(input.PositionOS, 1.0f), PrevWorldViewProjection).xyw; + + return output; +} + +//------------------------------------------------------------------------------------------------- +// Samples the EVSM shadow map +//------------------------------------------------------------------------------------------------- +float SampleShadowMapEVSM(in float3 shadowPos, in float3 shadowPosDX, + in float3 shadowPosDY, uint cascadeIdx) +{ + float2 exponents = GetEVSMExponents(PositiveExponent, NegativeExponent, + CascadeScales[cascadeIdx].xyz); + float2 warpedDepth = WarpDepth(shadowPos.z, exponents); + + float4 occluder = SunShadowMap.SampleGrad(EVSMSampler, float3(shadowPos.xy, cascadeIdx), + shadowPosDX.xy, shadowPosDY.xy); + + // Derivative of warping at depth + float2 depthScale = 0.0001f * exponents * warpedDepth; + float2 minVariance = depthScale * depthScale; + + float posContrib = ChebyshevUpperBound(occluder.xz, warpedDepth.x, minVariance.x, LightBleedingReduction); + float negContrib = ChebyshevUpperBound(occluder.yw, warpedDepth.y, minVariance.y, LightBleedingReduction); + float shadowContrib = posContrib; + shadowContrib = min(shadowContrib, negContrib); + + return shadowContrib; +} + +//------------------------------------------------------------------------------------------------- +// Samples the appropriate shadow map cascade +//------------------------------------------------------------------------------------------------- +float3 SampleShadowCascade(in float3 shadowPosition, in float3 shadowPosDX, + in float3 shadowPosDY, in uint cascadeIdx) +{ + shadowPosition += CascadeOffsets[cascadeIdx].xyz; + shadowPosition *= CascadeScales[cascadeIdx].xyz; + + shadowPosDX *= CascadeScales[cascadeIdx].xyz; + shadowPosDY *= CascadeScales[cascadeIdx].xyz; + + float3 cascadeColor = 1.0f; + + float shadow = SampleShadowMapEVSM(shadowPosition, shadowPosDX, shadowPosDY, cascadeIdx); + + return shadow * cascadeColor; +} + +//-------------------------------------------------------------------------------------- +// Computes the sun visibility term by performing the shadow test +//-------------------------------------------------------------------------------------- +float3 SunShadowVisibility(in float3 positionWS, in float depthVS) +{ + float3 shadowVisibility = 1.0f; + uint cascadeIdx = 0; + + // Project into shadow space + float3 samplePos = positionWS; + float3 shadowPosition = mul(float4(samplePos, 1.0f), ShadowMatrix).xyz; + float3 shadowPosDX = ddx(shadowPosition); + float3 shadowPosDY = ddy(shadowPosition); + + // Figure out which cascade to sample from + [unroll] + for(uint i = 0; i < NumCascades - 1; ++i) + { + [flatten] + if(depthVS > CascadeSplits[i]) + cascadeIdx = i + 1; + } + + shadowVisibility = SampleShadowCascade(shadowPosition, shadowPosDX, shadowPosDY, + cascadeIdx); + + return shadowVisibility; +} + +//------------------------------------------------------------------------------------------------- +// Computes the area light shadow visibility term +//------------------------------------------------------------------------------------------------- +float AreaLightShadowVisibility(in float3 positionWS) +{ + float3 shadowPos = positionWS - float3(AreaLightX, AreaLightY, AreaLightZ); + float3 shadowDistance = length(shadowPos); + float3 shadowDir = normalize(shadowPos); + + // Doing the max of the components tells us 2 things: which cubemap face we're going to use, + // and also what the projected distance is onto the major axis for that face. + float projectedDistance = max(max(abs(shadowPos.x), abs(shadowPos.y)), abs(shadowPos.z)); + + // Compute the project depth value that matches what would be stored in the depth buffer + // for the current cube map face. Note that we use a reversed infinite projection. + float nearClip = AreaLightSize; + float a = 0.0f; + float b = nearClip; + float z = projectedDistance * a + b; + float dbDistance = z / projectedDistance; + + return AreaLightShadowMap.SampleCmpLevelZero(PCFSampler, shadowDir, dbDistance + AreaLightShadowBias); +} + +//------------------------------------------------------------------------------------------------- +// Calculates the lighting result for an analytical light source +//------------------------------------------------------------------------------------------------- +float3 CalcLighting(in float3 normal, in float3 lightDir, in float3 lightColor, + in float3 diffuseAlbedo, in float3 specularAlbedo, in float roughness, + in float3 positionWS, inout float3 irradiance) +{ + float3 lighting = diffuseAlbedo * (1.0f / 3.14159f); + + float3 view = normalize(CameraPosWS - positionWS); + const float nDotL = saturate(dot(normal, lightDir)); + if(nDotL > 0.0f) + { + const float nDotV = saturate(dot(normal, view)); + float3 h = normalize(view + lightDir); + + float3 fresnel = Fresnel(specularAlbedo, h, lightDir); + + float specular = GGX_Specular(roughness, normal, h, view, lightDir); + lighting += specular * fresnel; + } + + irradiance += nDotL * lightColor; + return lighting * nDotL * lightColor; +} + +// ------------------------------------------------------------------------------------------------ +// Computes the irradiance for an SG light source using the selected approximation +// ------------------------------------------------------------------------------------------------ +float3 SGIrradiance(in SG lightingLobe, in float3 normal, in int diffuseMode) +{ + if(diffuseMode == SGDiffuseModes_Punctual) + return SGIrradiancePunctual(lightingLobe, normal); + else if(diffuseMode == SGDiffuseModes_Fitted) + return SGIrradianceFitted(lightingLobe, normal); + else + return SGIrradianceInnerProduct(lightingLobe, normal); +} + +// ------------------------------------------------------------------------------------------------ +// Computes the specular contribution from an SG light source +// ------------------------------------------------------------------------------------------------ +float3 SpecularTermSG(in SG light, in float3 normal, in float roughness, + in float3 view, in float3 specAlbedo) +{ + if(UseASGWarp) + return SpecularTermASGWarp(light, normal, roughness, view, specAlbedo); + else + return SpecularTermSGWarp(light, normal, roughness, view, specAlbedo); +} + +// ------------------------------------------------------------------------------------------------ +// Determine the exit radiance towards the eye from the SG's stored in the lightmap +// ------------------------------------------------------------------------------------------------ +void ComputeSGContribution(in Texture2DArray bakedLightingMap, in float2 lightMapUV, in float3 normalTS, + in float3 specularAlbedo, in float roughness, in float3 viewTS, in uint numSGs, + out float3 irradiance, out float3 specular) +{ + irradiance = 0.0f; + specular = 0.0f; + + for(uint i = 0; i < numSGs; ++i) + { + SG sg; + sg.Amplitude = bakedLightingMap.SampleLevel(LinearSampler, float3(lightMapUV, i), 0.0f).xyz; + sg.Axis = SGDirections[i].xyz; + sg.Sharpness = SGSharpness; + + irradiance += SGIrradiance(sg, normalTS, SGDiffuseMode); + specular += SpecularTermSG(sg, normalTS, roughness, viewTS, specularAlbedo); + } +} + +SH9Color GetSHSpecularBRDF(in float3 viewTS, in float3x3 tangentToWorld, in float3 normalTS, + in float3 specularAlbedo, in float sqrtRoughness) +{ + // Make a local coordinate frame in tangent space, with the x-axis + // aligned with the view direction and the z-axis aligned with the normal + float3 zBasis = normalTS; + float3 yBasis = normalize(cross(zBasis, viewTS)); + float3 xBasis = normalize(cross(yBasis, zBasis)); + float3x3 localFrame = float3x3(xBasis, yBasis, zBasis); + float viewAngle = saturate(dot(normalTS, viewTS)); + + // Look up coefficients from the SH lookup texture to make the SH BRDF + SH9Color shBrdf = (SH9Color)0.0f; + + [unroll] + for(uint i = 0; i < 3; ++i) + { + float4 t0 = SHSpecularLookupA.SampleLevel(LinearSampler, float3(viewAngle, sqrtRoughness, specularAlbedo[i]), 0.0f); + float2 t1 = SHSpecularLookupB.SampleLevel(LinearSampler, float3(viewAngle, sqrtRoughness, specularAlbedo[i]), 0.0f); + shBrdf.c[0][i] = t0.x; + shBrdf.c[2][i] = t0.y; + shBrdf.c[3][i] = t0.z; + shBrdf.c[6][i] = t0.w; + shBrdf.c[7][i] = t1.x; + shBrdf.c[8][i] = t1.y; + } + + // Transform the SH BRDF to tangent space + return RotateSH9(shBrdf, localFrame); +} + +struct SurfaceContext +{ + float3 ViewWS; + float3x3 TangentToWorld; + float3 NormalTS; + float3 NormalWS; + float3 VtxNormalWS; + float3 PositionWS; + float3 DiffuseAlbedo; + float3 SpecularAlbedo; + float SqrtRoughness; + float Roughness; +}; + +void ComputeIndirectFromLightmap(in SurfaceContext surface, in float2 lightMapUV, + out float3 indirectIrradiance, out float3 indirectSpecular) +{ + indirectIrradiance = 0.0f; + indirectSpecular = 0.0f; + + float3 viewTS = mul(surface.ViewWS, transpose(surface.TangentToWorld)); + + if(BakeMode == BakeModes_Diffuse) + { + indirectIrradiance = BakedLightingMap.SampleLevel(LinearSampler, float3(lightMapUV, 0.0f), 0.0f).xyz * Pi; + } + else if(BakeMode == BakeModes_HL2) + { + const float3 BasisDirs[3] = + { + float3(-1.0f / sqrt(6.0f), -1.0f / sqrt(2.0f), 1.0f / sqrt(3.0f)), + float3(-1.0f / sqrt(6.0f), 1.0f / sqrt(2.0f), 1.0f / sqrt(3.0f)), + float3(sqrt(2.0f / 3.0f), 0.0f, 1.0f / sqrt(3.0f)), + }; + + float weightSum = 0.0f; + + [unroll] + for(uint i = 0; i < 3; ++i) + { + float3 lightMap = BakedLightingMap.SampleLevel(LinearSampler, float3(lightMapUV, i), 0.0f).xyz; + indirectIrradiance += saturate(dot(surface.NormalTS, BasisDirs[i])) * lightMap; + } + } + else if(BakeMode == BakeModes_SH4) + { + SH4Color shRadiance; + + [unroll] + for(uint i = 0; i < 4; ++i) + shRadiance.c[i] = BakedLightingMap.SampleLevel(LinearSampler, float3(lightMapUV, i), 0.0f).xyz; + + indirectIrradiance = EvalSH4Irradiance(surface.NormalTS, shRadiance); + + SH4Color shSpecularBRDF = ConvertToSH4(GetSHSpecularBRDF(viewTS, surface.TangentToWorld, surface.NormalTS, surface.SpecularAlbedo, surface.SqrtRoughness)); + indirectSpecular = SHDotProduct(shSpecularBRDF, shRadiance); + } + else if(BakeMode == BakeModes_SH9) + { + SH9Color shRadiance; + + [unroll] + for(uint i = 0; i < 9; ++i) + shRadiance.c[i] = BakedLightingMap.SampleLevel(LinearSampler, float3(lightMapUV, i), 0.0f).xyz; + + indirectIrradiance = EvalSH9Irradiance(surface.NormalTS, shRadiance); + + SH9Color shSpecularBRDF = GetSHSpecularBRDF(viewTS, surface.TangentToWorld, surface.NormalTS, surface.SpecularAlbedo, surface.SqrtRoughness); + indirectSpecular = SHDotProduct(shSpecularBRDF, shRadiance); + } + else if(BakeMode == BakeModes_H4) + { + H4Color hbIrradiance; + + [unroll] + for(uint i = 0; i < 4; ++i) + hbIrradiance.c[i] = BakedLightingMap.SampleLevel(LinearSampler, float3(lightMapUV, i), 0.0f).xyz; + + indirectIrradiance = EvalH4(surface.NormalTS, hbIrradiance); + } + else if(BakeMode == BakeModes_H6) + { + H6Color hbIrradiance; + + [unroll] + for(uint i = 0; i < 6; ++i) + hbIrradiance.c[i] = BakedLightingMap.SampleLevel(LinearSampler, float3(lightMapUV, i), 0.0f).xyz; + + indirectIrradiance = EvalH6(surface.NormalTS, hbIrradiance); + } + else if(BakeMode == BakeModes_SG5) + { + ComputeSGContribution(BakedLightingMap, lightMapUV, surface.NormalTS, surface.SpecularAlbedo, surface.Roughness, + viewTS, 5, indirectIrradiance, indirectSpecular); + } + else if(BakeMode == BakeModes_SG6) + { + ComputeSGContribution(BakedLightingMap, lightMapUV, surface.NormalTS, surface.SpecularAlbedo, surface.Roughness, + viewTS, 6, indirectIrradiance, indirectSpecular); + } + else if(BakeMode == BakeModes_SG9) + { + ComputeSGContribution(BakedLightingMap, lightMapUV, surface.NormalTS, surface.SpecularAlbedo, surface.Roughness, + viewTS, 9, indirectIrradiance, indirectSpecular); + } + else if(BakeMode == BakeModes_SG12) + { + ComputeSGContribution(BakedLightingMap, lightMapUV, surface.NormalTS, surface.SpecularAlbedo, surface.Roughness, + viewTS, 12, indirectIrradiance, indirectSpecular); + } +} + +float Square(in float x) +{ + return x * x; +} + +float3 Square(in float3 x) +{ + return x * x; +} + +float4 Square(in float4 x) +{ + return x * x; +} + +void ComputeIndirectFromProbeCubeMaps(in SurfaceContext surface, out float3 indirectIrradiance, out float3 indirectSpecular) +{ + float3 normalizedSamplePos = saturate((surface.PositionWS - SceneMinBounds) / (SceneMaxBounds - SceneMinBounds)); + float3 probeDims = float3(ProbeResX, ProbeResY, ProbeResZ); + + float3 halfTexelSize = 0.5f / probeDims; + float3 baseSamplePos = saturate(normalizedSamplePos - halfTexelSize) * probeDims; + float3 lerpAmts = frac(baseSamplePos); + + float4 irradianceSum = 0.0f; + float4 irradianceNoVisSum = 0.0f; + float visSum = 0.0f; + for(uint i = 0; i < 8; ++i) + { + uint3 sampleOffset = uint3(i, i >> 1, i >> 2) & 0x1; + uint3 probeIndices = min(uint3(baseSamplePos) + sampleOffset, probeDims - 1.0f); + float probeIdx = uint(probeIndices.z) * (ProbeResX * ProbeResY) + uint(probeIndices.y) * ProbeResX + uint(probeIndices.x); + float3 triLinear = lerp(1.0f - lerpAmts, lerpAmts, float3(sampleOffset)); + float sampleWeight = triLinear.x * triLinear.y * triLinear.z; + + float3 probePosWS = lerp(SceneMinBounds, SceneMaxBounds, (probeIndices + 0.5f) / probeDims); + float3 dirToProbe = normalize(probePosWS - surface.PositionWS); + float distToProbe = length(probePosWS - surface.PositionWS); + + if(WeightProbesByNormal) + sampleWeight *= Square((dot(dirToProbe, surface.VtxNormalWS) + 1.0f) * 0.5f) + 0.2f; + + float sampleWeightNoVis = sampleWeight; + + if(WeightProbesByVisibility) + { + float maxDistance = length((SceneMaxBounds - SceneMinBounds) * rcp(float3(ProbeResX, ProbeResY, ProbeResZ))); + float compareDistance = saturate(distToProbe * rcp(maxDistance)); + + float2 distSample = ProbeDistanceCubeMaps.Sample(LinearSampler, float4(-dirToProbe, probeIdx)); + float visTerm = ChebyshevUpperBound(distSample, compareDistance, 0.0001f, 0.25f); + sampleWeight *= visTerm; + + visSum += visTerm; + } + + sampleWeight = max(0.0002f, sampleWeight); + + const float threshold = 0.2f; + if(sampleWeight < threshold) + sampleWeight *= Square(sampleWeight) / Square(threshold); + + float3 irradianceSample = ProbeIrradianceCubeMaps.Sample(LinearSampler, float4(surface.NormalWS, probeIdx)).xyz; + irradianceSum += float4(irradianceSample, 1.0f) * sampleWeight; + irradianceNoVisSum += float4(irradianceSample, 1.0f) * sampleWeightNoVis; + } + + irradianceSum = irradianceSum / irradianceSum.w; + irradianceNoVisSum = irradianceNoVisSum / irradianceNoVisSum.w; + + indirectIrradiance = sqrt(lerp(Square(irradianceNoVisSum.xyz), Square(irradianceSum.xyz), saturate(4.0f * visSum))); + + // indirectIrradiance = irradianceSum.xyz; + + indirectSpecular = 0.0f; +} + +float3 EvaluateProbeIrradiance(in float3 basis[MaxBasisCount], in float3 dir) +{ + float3 output = 0.0f; + + if(ProbeMode == ProbeModes_AmbientCube) + { + float3 ambientCubeDirs[6] = { float3(1, 0, 0), float3(0, 1, 0), float3(0, 0, 1), float3(-1, 0, 0), float3(0, -1, 0), float3(0, 0, -1) }; + float weightSum = 0.0f; + + [unroll] + for(uint i = 0; i < 6; ++i) + { + float weight = saturate(dot(dir, ambientCubeDirs[i])); + output += basis[i] * weight; + weightSum += weight; + } + + output /= weightSum; + } + else if(ProbeMode == ProbeModes_L1_SH) + { + SH4Color sh; + + [unroll] + for(uint i = 0; i < 4; ++i) + sh.c[i] = basis[i]; + + output = EvalSH4Irradiance(dir, sh); + } + else if(ProbeMode == ProbeModes_L2_SH) + { + SH9Color sh; + + [unroll] + for(uint i = 0; i < 9; ++i) + sh.c[i] = basis[i]; + + + output = EvalSH9Irradiance(dir, sh); + } + + return output; +} + + +void SampleVolumeTextures(in SurfaceContext surface, in float3 uvw, out float3 basis[MaxBasisCount]) +{ + if(ProbeMode == ProbeModes_AmbientCube) + { + [unroll] + for(uint i = 0; i < 6; ++i) + basis[i] = ProbeVolumeMaps[i].SampleLevel(LinearSampler, uvw, 0.0f).xyz; + } + else if(ProbeMode == ProbeModes_L1_SH) + { + [unroll] + for(uint i = 0; i < 4; ++i) + basis[i] = ProbeVolumeMaps[i].SampleLevel(LinearSampler, uvw, 0.0f).xyz; + } + else if(ProbeMode == ProbeModes_L2_SH) + { + [unroll] + for(uint i = 0; i < 9; ++i) + basis[i] = ProbeVolumeMaps[i].SampleLevel(LinearSampler, uvw, 0.0f).xyz; + } +} + +void ComputeIndirectFromProbeVolumeMaps(in SurfaceContext surface, out float3 indirectIrradiance, out float3 indirectSpecular) +{ + float3 normalizedSamplePos = saturate((surface.PositionWS - SceneMinBounds) / (SceneMaxBounds - SceneMinBounds)); + float3 uvw = normalizedSamplePos; + + indirectIrradiance = 0.0f; + indirectSpecular = 0.0f; + + float3 basis[MaxBasisCount]; + + [unroll] + for(uint i = 0; i < uint(MaxBasisCount); ++i) + basis[i] = 0.0f; + + SampleVolumeTextures(surface, uvw, basis); + + indirectIrradiance = EvaluateProbeIrradiance(basis, surface.NormalWS); +} + +// Convert to normalized [0, 1] space mapping to the voxel grid +float3 ToVoxelSpace(in float3 x) +{ + return (x - SceneMinBounds) / (SceneMaxBounds - SceneMinBounds); +} + +float ComputeVoxelAO(in SurfaceContext surface) +{ + const float3 coneDirections[6] = + { + float3(0, 0, 1), + float3(0, 0.866f, 0.5f), + float3(0.8236f, 0.2676f, 0.5f), + float3(0.51f, -0.7f, 0.5f), + float3(-0.5f, -0.7f, 0.5f), + float3(-0.82f, 0.5f, 0.267f), + }; + + const float coneWeights[6] = { Pi / 4, (3 * Pi) / 20, (3 * Pi) / 20, (3 * Pi) / 20, (3 * Pi) / 20, (3 * Pi) / 20 }; + + const float coneSpread = 0.325f; + + const float voxelRes = VoxelResolution * 0.5f; + const float voxelTexelSize = rcp(voxelRes); + + const float MaxMipLevel = 12.0f; + + float visibility = 0.0f; + float weightSum = 0.0f; + + const SamplerState voxelSampler = LinearSampler; + + [unroll] + for(uint coneIdx = 0; coneIdx < 6; ++ coneIdx) + { + const float3 coneDirWS = mul(coneDirections[coneIdx], surface.TangentToWorld); + const float3 startPosWS = surface.PositionWS + surface.VtxNormalWS * 0.05f; + + const float3 startPosVS = ToVoxelSpace(startPosWS); + const float3 coneDirVS = normalize(ToVoxelSpace(startPosWS + coneDirWS) - startPosVS); + + float traceDistance = 0.01f; + + float coneOcclusion = 0.0f; + + const uint MaxIterations = -1; + uint numIterations = 0; + + while(coneOcclusion < 1.0f && numIterations < MaxIterations && traceDistance < 0.5f) + { + const float3 tracePos = startPosVS + traceDistance * coneDirVS; + /*if(any(tracePos > 1.0f) || any(tracePos < 0.0f)) + break;*/ + + const float3 uvw = tracePos; + + const float mipLevel = min(log2(1.0f + coneSpread * 2.0f * traceDistance / voxelTexelSize), MaxMipLevel); + const float mipLevel2 = (mipLevel + 1) * (mipLevel + 1); + + float4 voxelSample = 0.0f; + float3 weights = coneDirVS * coneDirVS; + + [unroll] + for(uint i = 0; i < 3; ++i) + { + if(coneDirVS[i] >= 0.0f) + voxelSample += VoxelRadianceMips[i * 2 + 1].SampleLevel(voxelSampler, uvw, mipLevel) * weights[i]; + else + voxelSample += VoxelRadianceMips[i * 2 + 0].SampleLevel(voxelSampler, uvw, mipLevel) * weights[i]; + } + + // voxelSample = VoxelRadiance.SampleLevel(voxelSampler, uvw, 0.0f); + // voxelSample = VoxelRadianceMips[0].SampleLevel(voxelSampler, uvw, mipLevel); + + coneOcclusion += (1.0f - coneOcclusion) * voxelSample.w; + + traceDistance += mipLevel2 * voxelTexelSize; + + ++numIterations; + } + + visibility += saturate(1.0f - coneOcclusion) * coneWeights[coneIdx]; + weightSum += coneWeights[coneIdx]; + + // visibility = (numIterations == 4) * coneWeights[coneIdx] * 0.2f; + } + + visibility /= weightSum; + + return saturate(visibility); +} + +float3 ComputeVoxelIrradiance(in SurfaceContext surface) +{ + const float3 coneDirections[6] = + { + float3(0, 0, 1), + float3(0, 0.866f, 0.5f), + float3(0.8236f, 0.2676f, 0.5f), + float3(0.51f, -0.7f, 0.5f), + float3(-0.5f, -0.7f, 0.5f), + float3(-0.82f, 0.5f, 0.267f), + }; + + const float coneWeights[6] = { Pi / 4, (3 * Pi) / 20, (3 * Pi) / 20, (3 * Pi) / 20, (3 * Pi) / 20, (3 * Pi) / 20 }; + + const float coneSpread = 0.325f; + + const float voxelRes = VoxelResolution * 0.5f; + const float voxelTexelSize = rcp(voxelRes); + + const float MaxMipLevel = 12.0f; + + float3 irradiance = 0.0f; + float weightSum = 0.0f; + + const SamplerState voxelSampler = LinearSampler; + + [unroll] + for(uint coneIdx = 0; coneIdx < 6; ++ coneIdx) + { + const float3 coneDirWS = mul(coneDirections[coneIdx], surface.TangentToWorld); + const float3 startPosWS = surface.PositionWS + surface.VtxNormalWS * 0.55f; + + const float3 startPosVS = ToVoxelSpace(startPosWS); + const float3 coneDirVS = normalize(ToVoxelSpace(startPosWS + coneDirWS) - startPosVS); + + float traceDistance = 0.01f; + + float3 coneIrradiance = 0.0f; + float coneOcclusion = 0.0f; + + const uint MaxIterations = 6; + uint numIterations = 0; + + while(coneOcclusion < 1.0f && numIterations < MaxIterations && traceDistance < 0.75f) + { + const float3 tracePos = startPosVS + traceDistance * coneDirVS; + /*if(any(tracePos > 1.0f) || any(tracePos < 0.0f)) + break;*/ + + const float3 uvw = tracePos; + + const float mipLevel = min(log2(1.0f + coneSpread * 2.0f * traceDistance / voxelTexelSize), MaxMipLevel); + const float mipLevel2 = (mipLevel + 1) * (mipLevel + 1); + + float4 voxelSample = 0.0f; + float3 weights = coneDirVS * coneDirVS; + + [unroll] + for(uint i = 0; i < 3; ++i) + { + if(coneDirVS[i] >= 0.0f) + voxelSample += VoxelRadianceMips[i * 2 + 1].SampleLevel(voxelSampler, uvw, mipLevel) * weights[i]; + else + voxelSample += VoxelRadianceMips[i * 2 + 0].SampleLevel(voxelSampler, uvw, mipLevel) * weights[i]; + } + + // voxelSample = VoxelRadiance.SampleLevel(voxelSampler, uvw, 0.0f); + + coneIrradiance += (1.0f - coneOcclusion) * voxelSample.xyz; + coneOcclusion += (1.0f - coneOcclusion) * voxelSample.w; + + traceDistance += mipLevel2 * voxelTexelSize; + + ++numIterations; + } + + coneIrradiance *= Pi; + + float3 skyIrradiance = EvalSH9Irradiance(coneDirWS, SkySH); + coneIrradiance += (1.0f - coneOcclusion) * skyIrradiance * InvPi; + + irradiance += coneIrradiance * coneWeights[coneIdx]; + weightSum += coneWeights[coneIdx]; + } + + // irradiance /= weightSum; + + return irradiance; +} + + +//================================================================================================= +// Pixel Shader +//================================================================================================= +PSOutput PS(in PSInput input, in bool isFrontFace : SV_IsFrontFace) +{ + SurfaceContext surface; + surface.VtxNormalWS = normalize(input.NormalWS); + surface.NormalWS = surface.VtxNormalWS; + surface.PositionWS = input.PositionWS; + surface.ViewWS = normalize(CameraPosWS - surface.PositionWS); + + float2 uv = input.TexCoord; + + float3 normalTS = float3(0, 0, 1); + float3 tangentWS = normalize(input.TangentWS); + float3 bitangentWS = normalize(input.BitangentWS); + float3x3 tangentToWorld = float3x3(tangentWS, bitangentWS, surface.VtxNormalWS); + + if(EnableNormalMaps) + { + // Sample the normal map, and convert the normal to world space + normalTS.xy = NormalMap.Sample(AnisoSampler, uv).xy * 2.0f - 1.0f; + normalTS.z = sqrt(1.0f - saturate(normalTS.x * normalTS.x + normalTS.y * normalTS.y)); + normalTS = lerp(float3(0, 0, 1), normalTS, NormalMapIntensity); + surface.NormalWS = normalize(mul(normalTS, tangentToWorld)); + } + + surface.NormalTS = normalTS; + surface.TangentToWorld = tangentToWorld; + + // Gather material parameters + float3 albedoMap = 1.0f; + + if(EnableAlbedoMaps) + albedoMap = AlbedoMap.Sample(AnisoSampler, uv).xyz; + + float metallic = saturate(MetallicMap.Sample(AnisoSampler, uv)); + surface.DiffuseAlbedo = lerp(albedoMap.xyz, 0.0f, metallic) * DiffuseAlbedoScale * EnableDiffuse; + surface.SpecularAlbedo = lerp(0.03f, albedoMap.xyz, metallic) * EnableSpecular; + + surface.SqrtRoughness = RoughnessMap.Sample(AnisoSampler, uv); + surface.SqrtRoughness *= RoughnessScale; + surface.Roughness = surface.SqrtRoughness * surface.SqrtRoughness; + + float depthVS = input.DepthVS; + + // Add in the primary directional light + float3 lighting = 0.0f; + float3 irradiance = 0.0f; + + if(EnableDirectLighting && EnableSun) + { + float3 sunIrradiance = 0.0f; + float3 sunShadowVisibility = SunShadowVisibility(surface.PositionWS, depthVS); + float3 sunDirection = SunDirectionWS; + if(SunAreaLightApproximation) + { + float3 D = SunDirectionWS; + float3 R = reflect(-surface.ViewWS, surface.NormalWS); + float r = SinSunAngularRadius; + float d = CosSunAngularRadius; + float3 DDotR = dot(D, R); + float3 S = R - DDotR * D; + sunDirection = DDotR < d ? normalize(d * D + normalize(S) * r) : R; + } + lighting += CalcLighting(surface.NormalWS, sunDirection, SunIlluminance, surface.DiffuseAlbedo, surface.SpecularAlbedo, + surface.Roughness, surface.PositionWS, sunIrradiance) * sunShadowVisibility; + irradiance += sunIrradiance * sunShadowVisibility; + } + + if(EnableDirectLighting && EnableAreaLight && BakeDirectAreaLight == false) + { + float3 areaLightPos = float3(AreaLightX, AreaLightY, AreaLightZ); + float3 areaLightDir = normalize(areaLightPos - surface.PositionWS); + float areaLightDist = length(areaLightPos - surface.PositionWS); + SG lightLobe = MakeSphereSG(areaLightDir, AreaLightSize, AreaLightColor * FP16Scale, areaLightDist); + float3 sgIrradiance = SGIrradiance(lightLobe, surface.NormalWS, SGDiffuseMode); + + float areaLightVisibility = 1.0f; + if(EnableAreaLightShadows) + areaLightVisibility = AreaLightShadowVisibility(surface.PositionWS); + + lighting += sgIrradiance * (surface.DiffuseAlbedo / Pi) * areaLightVisibility; + lighting += SpecularTermSG(lightLobe, surface.NormalWS, surface.Roughness, surface.ViewWS, surface.SpecularAlbedo) * areaLightVisibility; + irradiance += sgIrradiance * areaLightVisibility; + } + + // Add in the indirect + if((EnableIndirectLighting || ViewIndirectSpecular || ViewIndirectDiffuse) && Voxelize_ == false) + { + float3 indirectIrradiance = 0.0f; + float3 indirectSpecular = 0.0f; + + if(UseProbes || ProbeRendering_) + { + if(ProbeMode == ProbeModes_CubeMap) + ComputeIndirectFromProbeCubeMaps(surface, indirectIrradiance, indirectSpecular); + else + ComputeIndirectFromProbeVolumeMaps(surface, indirectIrradiance, indirectSpecular); + } + else + ComputeIndirectFromLightmap(surface, input.LightMapUV, indirectIrradiance, indirectSpecular); + + // ################################################### + if(BakeWithVCT) + { + indirectIrradiance = ComputeVoxelIrradiance(surface); + indirectSpecular = 0.0f; + } + + if(EnableIndirectDiffuse) + { + irradiance += indirectIrradiance; + lighting += indirectIrradiance * (surface.DiffuseAlbedo / Pi); + } + + if(EnableIndirectSpecular) + lighting += indirectSpecular; + + #if !ProbeRendering_ + if(ViewIndirectSpecular) + lighting = indirectSpecular; + + if(ViewIndirectDiffuse) + lighting = indirectIrradiance / Pi; + #endif + } + + float illuminance = dot(irradiance, float3(0.2126f, 0.7152f, 0.0722f)); + + #if Voxelize_ + float3 voxelRadiance = clamp(irradiance * surface.DiffuseAlbedo * InvPi, 0.0f, FP16Max); + float3 voxelUVW = saturate((surface.PositionWS - SceneMinBounds) / (SceneMaxBounds - SceneMinBounds)); + int3 voxelCoord = int3(voxelUVW * VoxelResolution); + voxelCoord = clamp(voxelCoord, 0, VoxelResolution - 1); + + float3 prevVoxelRadiance = VoxelRadianceOutput[voxelCoord].xyz; + float prevVoxelCount = VoxelRadianceOutput[voxelCoord].w; + float3 newVoxelRadiance = lerp(prevVoxelRadiance, voxelRadiance, 1.0f / (prevVoxelCount + 1.0f)); + VoxelRadianceOutput[voxelCoord] = float4(newVoxelRadiance, prevVoxelCount + 1.0f); + #else + PSOutput output; + output.Lighting = clamp(float4(lighting, illuminance), 0.0f, FP16Max); + + if(isFrontFace == false) + output.Lighting = 0.0f; + + #if ProbeRendering_ + float distanceFromProbe = length(surface.PositionWS - CameraPosWS); + float maxDistance = length((SceneMaxBounds - SceneMinBounds) * rcp(float3(ProbeResX, ProbeResY, ProbeResZ))); + distanceFromProbe = saturate(distanceFromProbe * rcp(maxDistance)); + output.ProbeDistance = float2(distanceFromProbe, distanceFromProbe * distanceFromProbe); + #else + float2 prevPositionSS = (input.PrevPosition.xy / input.PrevPosition.z) * float2(0.5f, -0.5f) + 0.5f; + prevPositionSS *= RTSize; + output.Velocity = input.PositionSS.xy - prevPositionSS; + output.Velocity -= JitterOffset; + output.Velocity /= RTSize; + + // output.Lighting.xyz = ComputeVoxelAO(surface) * 8; + #endif + + return output; + #endif +} diff --git a/BakingLab/MeshBaker.cpp b/BakingLab/MeshBaker.cpp index a9612f9..653e650 100644 --- a/BakingLab/MeshBaker.cpp +++ b/BakingLab/MeshBaker.cpp @@ -43,7 +43,7 @@ struct GutterTexel // Returns the final monte-carlo weighting factor using the PDF of a cosine-weighted hemisphere static float CosineWeightedMonteCarloFactor(uint64 numSamples) { - // Integrating cosine factor about the hemisphere gives you Pi, and the PDF + // Integrating the cosine factor about the hemisphere gives you Pi, and the PDF // of a cosine-weighted hemisphere function is 1 / Pi. // So the final monte-carlo weighting factor is 1 / NumSamples return (1.0f / numSamples); @@ -57,7 +57,7 @@ static float HemisphereMonteCarloFactor(uint64 numSamples) static float SphereMonteCarloFactor(uint64 numSamples) { - // The area of a unit hemisphere is 2 * Pi, so the PDF is 1 / (2 * Pi) + // The area of a unit sphere is 4 * Pi, so the PDF is 1 / (4 * Pi) return ((4.0f * Pi) / numSamples); } @@ -1330,6 +1330,8 @@ MeshBakerStatus MeshBaker::Update(const Camera& camera, uint32 screenWidth, uint const bool32 showGroundTruth = AppSettings::ShowGroundTruth; + MeshBakerStatus status; + if(currentModel != input.SceneModel) { KillBakeThreads(); @@ -1543,12 +1545,15 @@ MeshBakerStatus MeshBaker::Update(const Camera& camera, uint32 screenWidth, uint || AppSettings::Turbidity.Changed() || AppSettings::HasSunDirChanged() || AppSettings::SunTintColor.Changed() || AppSettings::SunIntensityScale.Changed() || AppSettings::SunSize.Changed() || AppSettings::NormalizeSunIntensity.Changed() - || AppSettings::DiffuseAlbedoScale.Changed() || AppSettings::EnableAlbedoMaps.Changed()) + || AppSettings::DiffuseAlbedoScale.Changed() || AppSettings::EnableAlbedoMaps.Changed() + || AppSettings::CurrentScene.Changed()) { InterlockedIncrement64(&renderTag); InterlockedIncrement64(&bakeTag); currTile = 0; currBakeBatch = 0; + + status.BakingInvalidated = true; } // Change checks for baking only @@ -1589,7 +1594,6 @@ MeshBakerStatus MeshBaker::Update(const Camera& camera, uint32 screenWidth, uint currTile = 0; } - MeshBakerStatus status; status.GroundTruth = renderTextureSRV; status.LightMap = bakeTextureSRV; status.BakePoints = bakePointBuffer.SRView; diff --git a/BakingLab/MeshBaker.h b/BakingLab/MeshBaker.h index fade745..282a6f4 100644 --- a/BakingLab/MeshBaker.h +++ b/BakingLab/MeshBaker.h @@ -1,167 +1,178 @@ -//================================================================================================= -// -// Baking Lab -// by MJP and David Neubelt -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "PathTracer.h" -#include "SharedConstants.h" -#include "AppSettings.h" - -namespace SampleFramework11 -{ - class Model; - class Camera; - struct StructuredBuffer; -} - -using namespace SampleFramework11; - -struct RenderThreadContext; -struct RenderThreadData; -struct IntegrationSamples; -struct BakeThreadData; -struct GutterTexel; -struct Vertex; - -// Input to the baker -struct BakeInputData -{ - const Model* SceneModel = nullptr; - ID3D11Device* Device = nullptr; - ID3D11ShaderResourceView* EnvMaps[AppSettings::NumCubeMaps]; - TextureData EnvMapData[AppSettings::NumCubeMaps]; - - BakeInputData() - { - for(uint64 i = 0; i < ArraySize_(EnvMaps); ++i) - EnvMaps[i] = nullptr; - } -}; - -struct MeshBakerStatus -{ - ID3D11ShaderResourceView* GroundTruth = nullptr; - ID3D11ShaderResourceView* LightMap = nullptr; - ID3D11ShaderResourceView* BakePoints = nullptr; - uint64 NumBakePoints = 0; - float GroundTruthProgress = 0.0f; - float BakeProgress = 0.0f; - uint64 GroundTruthSampleCount = 0; - Float3 SGDirections[AppSettings::MaxSGCount]; - float SGSharpness = 0.0f; -}; - -class MeshBaker -{ - -public: - - MeshBaker(); - ~MeshBaker(); - - void Initialize(const BakeInputData& inputData); - void Shutdown(); - - MeshBakerStatus Update(const Camera& camera, uint32 screenWidth, uint32 screenHeight, - ID3D11DeviceContext* deviceContext, const Model* currentModel); - - // Read/Write Data shared with render threads - FixedArray renderBuffer; - FixedArray renderWeightBuffer; - volatile int64 currTile = 0; - - // Read-only data shared with render threads - volatile int64 renderTag = 0; - uint32 currWidth = 0; - uint32 currHeight = 0; - Float3 currCameraPos; - Quaternion currCameraOrientation; - Float4x4 currProj; - Float4x4 currViewProjInv; - bool killRenderThreads = false; - uint64 currNumTiles = 0; - - // Read/Write data shared with bake threads - FixedArray bakeResults[AppSettings::MaxBasisCount]; - volatile int64 currBakeBatch = 0; - - // Read-only data shared with bake threads - volatile int64 bakeTag = 0; - bool killBakeThreads = false; - uint64 currNumBakeBatches = 0; - uint64 currLightMapSize = 0; - BakeModes currBakeMode = BakeModes::Diffuse; - SolveModes currSolveMode = SolveModes::NNLS; - std::vector bakePoints; - std::vector gutterTexels; - - // Read-only data shared with both bake and render threads - BVHData sceneBVH; - TextureData envMap; - BakeInputData input; - -private: - - void KillBakeThreads(); - void StartBakeThreads(); - - void KillRenderThreads(); - void StartRenderThreads(); - - bool initialized = false; - - RTCDevice rtcDevice = nullptr; - - Random rng; - - static const uint64 NumStagingTextures = 2; - - ID3D11Texture2DPtr renderTexture; - ID3D11ShaderResourceViewPtr renderTextureSRV; - ID3D11Texture2DPtr renderStagingTextures[NumStagingTextures]; - uint64 renderStagingTextureIdx = 0; - - std::vector renderThreads; - std::vector renderThreadData; - std::vector renderSamples; - SampleModes renderSampleMode = SampleModes::Random; - uint64 numRenderSamples = 0; - - bool renderThreadsSuspended = false; - - ID3D11Texture2DPtr bakeTexture; - ID3D11ShaderResourceViewPtr bakeTextureSRV; - uint64 bakeStagingTextureIdx = 0; - ID3D11Texture2DPtr bakeStagingTextures[NumStagingTextures]; - uint64 bakeTextureUpdateIdx = 0; - - uint64 numThreads = 0; - std::vector bakeThreads; - std::vector bakeThreadData; - std::vector bakeSamples; - SampleModes bakeSampleMode = SampleModes::Random; - uint64 numBakeSamples = 0; - StructuredBuffer bakePointBuffer; - bool bakeThreadsSuspended = false; - - Float3 sgDirections[AppSettings::MaxSGCount]; - float sgSharpness = 0.0f; - - int64 lastTileNum = INT64_MAX; +//================================================================================================= +// +// Baking Lab +// by MJP and David Neubelt +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "PathTracer.h" +#include "SharedConstants.h" +#include "AppSettings.h" + +namespace SampleFramework11 +{ + class Model; + class Camera; + struct StructuredBuffer; +} + +using namespace SampleFramework11; + +struct RenderThreadContext; +struct RenderThreadData; +struct IntegrationSamples; +struct BakeThreadData; +struct GutterTexel; +struct Vertex; + +// Input to the baker +struct BakeInputData +{ + const Model* SceneModel = nullptr; + ID3D11Device* Device = nullptr; + ID3D11ShaderResourceView* EnvMaps[AppSettings::NumCubeMaps]; + TextureData EnvMapData[AppSettings::NumCubeMaps]; + + BakeInputData() + { + for(uint64 i = 0; i < ArraySize_(EnvMaps); ++i) + EnvMaps[i] = nullptr; + } +}; + +struct MeshBakerStatus +{ + ID3D11ShaderResourceView* GroundTruth = nullptr; + ID3D11ShaderResourceView* LightMap = nullptr; + ID3D11ShaderResourceView* BakePoints = nullptr; + ID3D11ShaderResourceView* ProbeIrradianceCubeMap = nullptr; + ID3D11ShaderResourceView* ProbeDistanceCubeMap = nullptr; + ID3D11ShaderResourceView* ProbeVolumeMaps[AppSettings::MaxBasisCount] = { }; + ID3D11ShaderResourceView* ProbeDistanceVolumeMaps[AppSettings::MaxBasisCount] = { }; + ID3D11ShaderResourceView* VoxelRadiance = nullptr; + ID3D11ShaderResourceView* VoxelRadianceMips[6] = { }; + uint64 NumBakePoints = 0; + float GroundTruthProgress = 0.0f; + float BakeProgress = 0.0f; + uint64 GroundTruthSampleCount = 0; + Float3 SGDirections[AppSettings::MaxSGCount]; + float SGSharpness = 0.0f; + Float3 SceneMinBounds; + Float3 SceneMaxBounds; + bool32 BakingInvalidated = false; + float ProbeBakeProgress = 0.0f; + SH9Color SkySH; +}; + +class MeshBaker +{ + +public: + + MeshBaker(); + ~MeshBaker(); + + void Initialize(const BakeInputData& inputData); + void Shutdown(); + + MeshBakerStatus Update(const Camera& camera, uint32 screenWidth, uint32 screenHeight, + ID3D11DeviceContext* deviceContext, const Model* currentModel); + + // Read/Write Data shared with render threads + FixedArray renderBuffer; + FixedArray renderWeightBuffer; + volatile int64 currTile = 0; + + // Read-only data shared with render threads + volatile int64 renderTag = 0; + uint32 currWidth = 0; + uint32 currHeight = 0; + Float3 currCameraPos; + Quaternion currCameraOrientation; + Float4x4 currProj; + Float4x4 currViewProjInv; + bool killRenderThreads = false; + uint64 currNumTiles = 0; + + // Read/Write data shared with bake threads + FixedArray bakeResults[AppSettings::MaxBasisCount]; + volatile int64 currBakeBatch = 0; + + // Read-only data shared with bake threads + volatile int64 bakeTag = 0; + bool killBakeThreads = false; + uint64 currNumBakeBatches = 0; + uint64 currLightMapSize = 0; + BakeModes currBakeMode = BakeModes::Diffuse; + SolveModes currSolveMode = SolveModes::NNLS; + std::vector bakePoints; + std::vector gutterTexels; + + // Read-only data shared with both bake and render threads + BVHData sceneBVH; + TextureData envMap; + BakeInputData input; + +private: + + void KillBakeThreads(); + void StartBakeThreads(); + + void KillRenderThreads(); + void StartRenderThreads(); + + bool initialized = false; + + RTCDevice rtcDevice = nullptr; + + Random rng; + + static const uint64 NumStagingTextures = 2; + + ID3D11Texture2DPtr renderTexture; + ID3D11ShaderResourceViewPtr renderTextureSRV; + ID3D11Texture2DPtr renderStagingTextures[NumStagingTextures]; + uint64 renderStagingTextureIdx = 0; + + std::vector renderThreads; + std::vector renderThreadData; + std::vector renderSamples; + SampleModes renderSampleMode = SampleModes::Random; + uint64 numRenderSamples = 0; + + bool renderThreadsSuspended = false; + + ID3D11Texture2DPtr bakeTexture; + ID3D11ShaderResourceViewPtr bakeTextureSRV; + uint64 bakeStagingTextureIdx = 0; + ID3D11Texture2DPtr bakeStagingTextures[NumStagingTextures]; + uint64 bakeTextureUpdateIdx = 0; + + uint64 numThreads = 0; + std::vector bakeThreads; + std::vector bakeThreadData; + std::vector bakeSamples; + SampleModes bakeSampleMode = SampleModes::Random; + uint64 numBakeSamples = 0; + StructuredBuffer bakePointBuffer; + bool bakeThreadsSuspended = false; + + Float3 sgDirections[AppSettings::MaxSGCount]; + float sgSharpness = 0.0f; + + int64 lastTileNum = INT64_MAX; }; \ No newline at end of file diff --git a/BakingLab/MeshRenderer.cpp b/BakingLab/MeshRenderer.cpp index e6ded79..b1c2f9d 100644 --- a/BakingLab/MeshRenderer.cpp +++ b/BakingLab/MeshRenderer.cpp @@ -1,1060 +1,1409 @@ -//================================================================================================= -// -// Baking Lab -// by MJP and David Neubelt -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -#include - -#include "MeshRenderer.h" - -#include -#include -#include -#include - -#include "AppSettings.h" -#include "SharedConstants.h" -#include "MeshBaker.h" - -// Constants -static const float ShadowNearClip = 1.0f; -static const float FilterSize = 7.0f; -static const uint32 SampleRadius = 3; -static const float OffsetScale = 0.0f; -static const float LightBleedingReduction = 0.10f; -static const float PositiveExponent = 40.0f; -static const float NegativeExponent = 8.0f; -static const uint32 ShadowMapSize = 1024; -static const uint32 ShadowMSAASamples = 4; -static const uint32 ShadowAnisotropy = 16; -static const bool EnableShadowMips = true; - -static void GenerateHemisphere(uint64 NumUSlices, uint64 NumVSlices, ID3D11Device* device, - ID3D11BufferPtr& vtxBuffer, ID3D11BufferPtr& idxBuffer, uint64& numIndices) -{ - Assert_(NumUSlices >= 3); - Assert_(NumVSlices >= 2); - - std::vector hemisphereVerts; - - // Add the vert at the top - hemisphereVerts.push_back(Float3(0.0f, 0.0f, 1.0f)); - - // Add the rings - for(uint64 v = 0; v < NumVSlices; ++v) - { - for(uint64 u = 0; u < NumUSlices; ++u) - { - const float theta = ((v + 1.0f) / NumVSlices) * Pi_2; - const float phi = (float(u) / NumUSlices) * Pi2; - - Float3 pos; - pos.x = std::sin(theta) * std::cos(phi); - pos.y = std::sin(theta) * std::sin(phi); - pos.z = std::cos(theta); - - hemisphereVerts.push_back(pos); - } - } - - Assert_(hemisphereVerts.size() <= UINT32_MAX); - - // Add the top ring of triangles - std::vector hemisphereIndices; - for(uint32 u = 0; u < NumUSlices; ++u) - { - hemisphereIndices.push_back(0); - hemisphereIndices.push_back(u + 1); - - if(u < NumUSlices - 1) - hemisphereIndices.push_back(u + 2); - else - hemisphereIndices.push_back(1); - } - - // Add the rest of the rings - uint32 prevRowStart = 1; - uint32 currRowStart = uint32(NumUSlices + 1); - for(uint32 v = 1; v < NumVSlices; ++v) - { - for(uint32 u = 0; u < NumUSlices; ++u) - { - uint32 nextBottom = currRowStart + u + 1; - uint32 nextTop = prevRowStart + u + 1; - if(u == NumUSlices - 1) - { - nextBottom = currRowStart; - nextTop = prevRowStart; - } - - hemisphereIndices.push_back(prevRowStart + u); - hemisphereIndices.push_back(currRowStart + u); - hemisphereIndices.push_back(nextBottom); - hemisphereIndices.push_back(nextBottom); - hemisphereIndices.push_back(nextTop); - hemisphereIndices.push_back(prevRowStart + u); - } - - prevRowStart = currRowStart; - currRowStart += uint32(NumUSlices); - } - - numIndices = hemisphereIndices.size(); - - D3D11_BUFFER_DESC bufferDesc; - bufferDesc.ByteWidth = sizeof(Float3) * uint32(hemisphereVerts.size()); - bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; - bufferDesc.CPUAccessFlags = 0; - bufferDesc.MiscFlags = 0; - bufferDesc.StructureByteStride = 0; - bufferDesc.Usage = D3D11_USAGE_IMMUTABLE; - - D3D11_SUBRESOURCE_DATA initData; - initData.pSysMem = hemisphereVerts.data(); - initData.SysMemPitch = 0; - initData.SysMemSlicePitch = 0; - DXCall(device->CreateBuffer(&bufferDesc, &initData, &vtxBuffer)); - - bufferDesc.ByteWidth = sizeof(uint32) * uint32(hemisphereIndices.size()); - bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; - initData.pSysMem = hemisphereIndices.data(); - DXCall(device->CreateBuffer(&bufferDesc, &initData, &idxBuffer)); -} - -static void GenerateSphere(uint64 NumUSlices, uint64 NumVSlices, ID3D11Device* device, - ID3D11BufferPtr& vtxBuffer, ID3D11BufferPtr& idxBuffer, uint64& numIndices) -{ - Assert_(NumUSlices >= 3); - Assert_(NumVSlices >= 3); - - std::vector sphereVerts; - - // Add the vert at the top - sphereVerts.push_back(Float3(0.0f, 0.0f, 1.0f)); - - // Add the rings - for(uint64 v = 0; v < NumVSlices - 1; ++v) - { - for(uint64 u = 0; u < NumUSlices; ++u) - { - const float theta = ((v + 1.0f) / NumVSlices) * Pi; - const float phi = (float(u) / NumUSlices) * Pi2; - - Float3 pos; - pos.x = std::sin(theta) * std::cos(phi); - pos.y = std::sin(theta) * std::sin(phi); - pos.z = std::cos(theta); - - sphereVerts.push_back(pos); - } - } - - // Add the vert at the bottom - const uint32 lastVertIdx = uint32(sphereVerts.size()); - sphereVerts.push_back(Float3(0.0f, 0.0f, -1.0f)); - - Assert_(sphereVerts.size() <= UINT32_MAX); - - // Add the top ring of triangles - std::vector sphereIndices; - for(uint32 u = 0; u < NumUSlices; ++u) - { - sphereIndices.push_back(0); - sphereIndices.push_back(u + 1); - - if(u < NumUSlices - 1) - sphereIndices.push_back(u + 2); - else - sphereIndices.push_back(1); - } - - // Add the rest of the rings - uint32 prevRowStart = 1; - uint32 currRowStart = uint32(NumUSlices + 1); - for(uint32 v = 1; v < NumVSlices - 1; ++v) - { - for(uint32 u = 0; u < NumUSlices; ++u) - { - uint32 nextBottom = currRowStart + u + 1; - uint32 nextTop = prevRowStart + u + 1; - if(u == NumUSlices - 1) - { - nextBottom = currRowStart; - nextTop = prevRowStart; - } - - sphereIndices.push_back(prevRowStart + u); - sphereIndices.push_back(currRowStart + u); - sphereIndices.push_back(nextBottom); - sphereIndices.push_back(nextBottom); - sphereIndices.push_back(nextTop); - sphereIndices.push_back(prevRowStart + u); - } - - prevRowStart = currRowStart; - currRowStart += uint32(NumUSlices); - } - - // Add the last ring at the bottom - const uint32 lastRingStart = uint32(lastVertIdx - NumUSlices); - for(uint32 u = 0; u < NumUSlices; ++u) - { - sphereIndices.push_back(lastVertIdx); - sphereIndices.push_back(lastRingStart + u); - - if(u < NumUSlices - 1) - sphereIndices.push_back(lastRingStart + u + 1); - else - sphereIndices.push_back(lastRingStart); - } - - numIndices = sphereIndices.size(); - - D3D11_BUFFER_DESC bufferDesc; - bufferDesc.ByteWidth = sizeof(Float3) * uint32(sphereVerts.size()); - bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; - bufferDesc.CPUAccessFlags = 0; - bufferDesc.MiscFlags = 0; - bufferDesc.StructureByteStride = 0; - bufferDesc.Usage = D3D11_USAGE_IMMUTABLE; - - D3D11_SUBRESOURCE_DATA initData; - initData.pSysMem = sphereVerts.data(); - initData.SysMemPitch = 0; - initData.SysMemSlicePitch = 0; - DXCall(device->CreateBuffer(&bufferDesc, &initData, &vtxBuffer)); - - bufferDesc.ByteWidth = sizeof(uint32) * uint32(sphereIndices.size()); - bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; - initData.pSysMem = sphereIndices.data(); - DXCall(device->CreateBuffer(&bufferDesc, &initData, &idxBuffer)); -} - -MeshRenderer::MeshRenderer() : currFrame(0), sceneModel(nullptr), - numHemisphereIndices(0), numAreaLightIndices(0) -{ -} - -void MeshRenderer::LoadShaders() -{ - // Load the mesh shaders - meshDepthVS = CompileVSFromFile(device, L"DepthOnly.hlsl", "VS", "vs_5_0"); - meshVS = CompileVSFromFile(device, L"Mesh.hlsl", "VS", "vs_5_0"); - meshPS = CompilePSFromFile(device, L"Mesh.hlsl", "PS", "ps_5_0"); - - areaLightVS = CompileVSFromFile(device, L"AreaLight.hlsl", "VS", "vs_5_0"); - areaLightPS = CompilePSFromFile(device, L"AreaLight.hlsl", "PS", "ps_5_0"); - - visualizerVS = CompileVSFromFile(device, L"BakeDataVisualizer.hlsl", "VS", "vs_5_0"); - visualizerPS = CompilePSFromFile(device, L"BakeDataVisualizer.hlsl", "PS", "ps_5_0"); - - fullScreenVS = CompileVSFromFile(device, L"EVSMConvert.hlsl", "FullScreenVS"); - - CompileOptions opts; - opts.Add("MSAASamples_", ShadowMSAASamples); - evsmConvertPS = CompilePSFromFile(device, L"EVSMConvert.hlsl", "ConvertToEVSM", "ps_5_0", opts); - - opts.Reset(); - opts.Add("Horizontal_", 1); - opts.Add("Vertical_", 0); - opts.Add("SampleRadius_", SampleRadius); - evsmBlurH = CompilePSFromFile(device, L"EVSMConvert.hlsl", "BlurEVSM", "ps_5_0", opts); - - opts.Reset(); - opts.Add("Horizontal_", 0); - opts.Add("Vertical_", 1); - opts.Add("SampleRadius_", SampleRadius); - evsmBlurV = CompilePSFromFile(device, L"EVSMConvert.hlsl", "BlurEVSM", "ps_5_0", opts); - - opts.Reset(); - opts.Add("MSAA_", 0); - depthReductionInitialCS[0] = CompileCSFromFile(device, L"DepthReduction.hlsl", "DepthReductionInitialCS", "cs_5_0", opts); - - opts.Reset(); - opts.Add("MSAA_", 1); - depthReductionInitialCS[1] = CompileCSFromFile(device, L"DepthReduction.hlsl", "DepthReductionInitialCS", "cs_5_0", opts); - - depthReductionCS = CompileCSFromFile(device, L"DepthReduction.hlsl", "DepthReductionCS"); -} - -void MeshRenderer::CreateShadowMaps() -{ - // Create the shadow map as a texture atlas - sunShadowDepthMap.Initialize(device, ShadowMapSize, ShadowMapSize, DXGI_FORMAT_D24_UNORM_S8_UINT, true, - ShadowMSAASamples, 0, 1); - - DXGI_FORMAT smFmt = DXGI_FORMAT_R32G32B32A32_FLOAT; - uint32 numMips = EnableShadowMips ? 0 : 1; - sunVSM.Initialize(device, ShadowMapSize, ShadowMapSize, smFmt, numMips, 1, 0, - EnableShadowMips, false, NumCascades, false); - - tempVSM.Initialize(device, ShadowMapSize, ShadowMapSize, smFmt, 1, 1, 0, false, false, 1, false); - - areaLightShadowMap.Initialize(device, ShadowMapSize, ShadowMapSize, DXGI_FORMAT_D32_FLOAT, true, 1, 0, 6, true); -} - -// Loads resources -void MeshRenderer::Initialize(ID3D11Device* device, ID3D11DeviceContext* context, const Model* model) -{ - this->device = device; - - blendStates.Initialize(device); - rasterizerStates.Initialize(device); - depthStencilStates.Initialize(device); - samplerStates.Initialize(device); - - meshVSConstants.Initialize(device); - meshPSConstants.Initialize(device); - areaLightConstants.Initialize(device); - visualizerConstants.Initialize(device); - evsmConstants.Initialize(device); - reductionConstants.Initialize(device); - - shSpecularLookupA = LoadTexture(device, L"..\\Content\\Textures\\SHSpecularA.dds"); - shSpecularLookupB = LoadTexture(device, L"..\\Content\\Textures\\SHSpecularB.dds"); - - LoadShaders(); - - D3D11_RASTERIZER_DESC rsDesc = RasterizerStates::NoCullDesc(); - rsDesc.DepthClipEnable = false; - DXCall(device->CreateRasterizerState(&rsDesc, &noZClipRSState)); - - D3D11_SAMPLER_DESC sampDesc = SamplerStates::AnisotropicDesc(); - sampDesc.MaxAnisotropy = ShadowAnisotropy; - DXCall(device->CreateSamplerState(&sampDesc, &evsmSampler)); - - // Create the staging textures for reading back the reduced depth buffer - for(uint32 i = 0; i < ReadbackLatency; ++i) - reductionStagingTextures[i].Initialize(device, 1, 1, DXGI_FORMAT_R16G16_UNORM); - - CreateShadowMaps(); - - GenerateHemisphere(16, 4, device, hemisphereVB, hemisphereIB, numHemisphereIndices); - - GenerateSphere(256, 192, device, areaLightVB, areaLightIB, numAreaLightIndices); - - D3D11_INPUT_ELEMENT_DESC elements[1]; - elements[0].AlignedByteOffset = 0; - elements[0].Format = DXGI_FORMAT_R32G32B32_FLOAT; - elements[0].InputSlot = 0; - elements[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; - elements[0].InstanceDataStepRate = 0; - elements[0].SemanticName = "POSITION"; - elements[0].SemanticIndex = 0; - - DXCall(device->CreateInputLayout(elements, 1, visualizerVS->ByteCode->GetBufferPointer(), - visualizerVS->ByteCode->GetBufferSize(), &visualizerInputLayout)); - - DXCall(device->CreateInputLayout(elements, 1, areaLightVS->ByteCode->GetBufferPointer(), - areaLightVS->ByteCode->GetBufferSize(), &areaLightInputLayout)); - - SetModel(model); -} - -void MeshRenderer::SetModel(const Model* model) -{ - Assert_(model != nullptr); - sceneModel = model; - - meshInputLayouts.clear(); - meshDepthInputLayouts.clear(); - - for(uint64 i = 0; i < sceneModel->Meshes().size(); ++i) - { - // Generate input layouts for the scene meshes - const Mesh& mesh = sceneModel->Meshes()[i]; - ID3D11InputLayoutPtr inputLayout; - DXCall(device->CreateInputLayout(mesh.InputElements(), mesh.NumInputElements(), - meshVS->ByteCode->GetBufferPointer(), meshVS->ByteCode->GetBufferSize(), &inputLayout)); - meshInputLayouts.push_back(inputLayout); - - DXCall(device->CreateInputLayout(mesh.InputElements(), mesh.NumInputElements(), - meshDepthVS->ByteCode->GetBufferPointer(), meshDepthVS->ByteCode->GetBufferSize(), &inputLayout)); - meshDepthInputLayouts.push_back(inputLayout); - } -} - -void MeshRenderer::Update(const Camera& camera, Float2 jitterOffset) -{ - prevVP = currVP; - currVP = camera.ViewProjectionMatrix(); - if(firstFrame) - { - prevVP = currVP; - firstFrame = false; - } - - meshPSConstants.Data.JitterOffset = jitterOffset; - areaLightConstants.Data.JitterOffset = jitterOffset; -} - -void MeshRenderer::OnResize(uint32 width, uint32 height) -{ - depthReductionTargets.clear(); - - uint32 w = width; - uint32 h = height; - - while(w > 1 || h > 1) - { - w = DispatchSize(ReductionTGSize, w); - h = DispatchSize(ReductionTGSize, h); - - RenderTarget2D rt; - rt.Initialize(device, w, h, DXGI_FORMAT_R16G16_UNORM, 1, 1, 0, false, true); - depthReductionTargets.push_back(rt); - } - - meshPSConstants.Data.RTSize.x = float(width); - meshPSConstants.Data.RTSize.y = float(height); - - areaLightConstants.Data.RTSize = meshPSConstants.Data.RTSize; -} - -void MeshRenderer::ReduceDepth(ID3D11DeviceContext* context, DepthStencilBuffer& depthTarget, - const Camera& camera) -{ - PIXEvent event(L"Depth Reduction"); - - reductionConstants.Data.Projection = Float4x4::Transpose(camera.ProjectionMatrix()); - reductionConstants.Data.NearClip = camera.NearClip(); - reductionConstants.Data.FarClip = camera.FarClip(); - reductionConstants.Data.TextureSize = Uint2(depthTarget.Width, depthTarget.Height); - reductionConstants.Data.NumSamples = depthTarget.MultiSamples; - reductionConstants.ApplyChanges(context); - reductionConstants.SetCS(context, 0); - - ID3D11RenderTargetView* rtvs[1] = { NULL }; - context->OMSetRenderTargets(1, rtvs, NULL); - - ID3D11UnorderedAccessView* uavs[1] = { depthReductionTargets[0].UAView }; - context->CSSetUnorderedAccessViews(0, 1, uavs, NULL); - - ID3D11ShaderResourceView* srvs[1] = { depthTarget.SRView }; - context->CSSetShaderResources(0, 1, srvs); - - const bool msaa = depthTarget.MultiSamples > 1; - - ID3D11ComputeShader* shader = depthReductionInitialCS[msaa ? 1 : 0]; - context->CSSetShader(shader, NULL, 0); - - uint32 dispatchX = depthReductionTargets[0].Width; - uint32 dispatchY = depthReductionTargets[0].Height; - context->Dispatch(dispatchX, dispatchY, 1); - - uavs[0] = NULL; - context->CSSetUnorderedAccessViews(0, 1, uavs, NULL); - - srvs[0] = NULL; - context->CSSetShaderResources(0, 1, srvs); - - context->CSSetShader(depthReductionCS, NULL, 0); - - for(uint32 i = 1; i < depthReductionTargets.size(); ++i) - { - RenderTarget2D& srcTexture = depthReductionTargets[i - 1]; - reductionConstants.Data.TextureSize.x = srcTexture.Width; - reductionConstants.Data.TextureSize.y = srcTexture.Height; - reductionConstants.Data.NumSamples = srcTexture.MultiSamples; - reductionConstants.ApplyChanges(context); - - uavs[0] = depthReductionTargets[i].UAView; - context->CSSetUnorderedAccessViews(0, 1, uavs, NULL); - - srvs[0] = srcTexture.SRView; - context->CSSetShaderResources(0, 1, srvs); - - dispatchX = depthReductionTargets[i].Width; - dispatchY = depthReductionTargets[i].Height; - context->Dispatch(dispatchX, dispatchY, 1); - - uavs[0] = NULL; - context->CSSetUnorderedAccessViews(0, 1, uavs, NULL); - - srvs[0] = NULL; - context->CSSetShaderResources(0, 1, srvs); - } - - // Copy to a staging texture - ID3D11Texture2D* lastTarget = depthReductionTargets[depthReductionTargets.size() - 1].Texture; - context->CopyResource(reductionStagingTextures[currFrame % ReadbackLatency].Texture, lastTarget); - - ++currFrame; - - if(currFrame >= ReadbackLatency) - { - StagingTexture2D& stagingTexture = reductionStagingTextures[currFrame % ReadbackLatency]; - - uint32 pitch; - const uint16* texData = reinterpret_cast(stagingTexture.Map(context, 0, pitch)); - reductionDepth.x = texData[0] / static_cast(0xffff); - reductionDepth.y = texData[1] / static_cast(0xffff); - - stagingTexture.Unmap(context, 0); - } - else - { - reductionDepth = Float2(0.0f, 1.0f); - } -} - -// Convert to an EVSM map -void MeshRenderer::ConvertToEVSM(ID3D11DeviceContext* context, uint32 cascadeIdx, Float3 cascadeScale) -{ - PIXEvent event(L"EVSM Conversion"); - - float blendFactor[4] = {1, 1, 1, 1}; - context->OMSetBlendState(blendStates.BlendDisabled(), blendFactor, 0xFFFFFFFF); - context->RSSetState(rasterizerStates.NoCull()); - context->OMSetDepthStencilState(depthStencilStates.DepthDisabled(), 0); - ID3D11Buffer* vbs[1] = { NULL }; - uint32 strides[1] = { 0 }; - uint32 offsets[1] = { 0 }; - context->IASetVertexBuffers(0, 1, vbs, strides, offsets); - context->IASetIndexBuffer(NULL, DXGI_FORMAT_R32_UINT, 0); - context->IASetInputLayout(NULL); - - SetViewport(context, sunVSM.Width, sunVSM.Height); - - evsmConstants.Data.PositiveExponent = PositiveExponent; - evsmConstants.Data.NegativeExponent = NegativeExponent; - evsmConstants.Data.CascadeScale = meshPSConstants.Data.CascadeScales[cascadeIdx].To3D(); - evsmConstants.Data.FilterSize = 1.0f; - evsmConstants.Data.ShadowMapSize.x = float(sunVSM.Width); - evsmConstants.Data.ShadowMapSize.y = float(sunVSM.Height); - evsmConstants.ApplyChanges(context); - evsmConstants.SetPS(context, 0); - - context->VSSetShader(fullScreenVS, NULL, 0); - context->PSSetShader(evsmConvertPS, NULL, 0); - - ID3D11RenderTargetView* rtvs[1] = { sunVSM.RTVArraySlices[cascadeIdx] }; - context->OMSetRenderTargets(1, rtvs, NULL); - - ID3D11ShaderResourceView* srvs[1] = { sunShadowDepthMap.SRView }; - context->PSSetShaderResources(0, 1, srvs); - - context->Draw(3, 0); - - srvs[0] = NULL; - context->PSSetShaderResources(0, 1, srvs); - - const float FilterSizeU = std::max(FilterSize * cascadeScale.x, 1.0f); - const float FilterSizeV = std::max(FilterSize * cascadeScale.y, 1.0f); - - if(FilterSizeU > 1.0f || FilterSizeV > 1.0f) - { - // Horizontal pass - evsmConstants.Data.FilterSize = FilterSizeU; - evsmConstants.ApplyChanges(context); - - uint32 sampleRadiusU = static_cast((FilterSizeU / 2) + 0.499f); - - rtvs[0] = tempVSM.RTView; - context->OMSetRenderTargets(1, rtvs, NULL); - - srvs[0] = sunVSM.SRVArraySlices[cascadeIdx]; - context->PSSetShaderResources(0, 1, srvs); - - context->PSSetShader(evsmBlurH, NULL, 0); - - context->Draw(3, 0); - - srvs[0] = NULL; - context->PSSetShaderResources(0, 1, srvs); - - // Vertical pass - evsmConstants.Data.FilterSize = FilterSizeV; - evsmConstants.ApplyChanges(context); - - uint32 sampleRadiusV = static_cast((FilterSizeV / 2) + 0.499f); - - rtvs[0] = sunVSM.RTVArraySlices[cascadeIdx]; - context->OMSetRenderTargets(1, rtvs, NULL); - - srvs[0] = tempVSM.SRView; - context->PSSetShaderResources(0, 1, srvs); - - context->PSSetShader(evsmBlurV, NULL, 0); - - context->Draw(3, 0); - - srvs[0] = NULL; - context->PSSetShaderResources(0, 1, srvs); - } - - if(EnableShadowMips && cascadeIdx == NumCascades - 1) - context->GenerateMips(sunVSM.SRView); -} - -// Renders all meshes in the model, with shadows -void MeshRenderer::RenderMainPass(ID3D11DeviceContext* context, const Camera& camera, const MeshBakerStatus& status) -{ - PIXEvent event(L"Mesh Rendering"); - - // Set states - float blendFactor[4] = {1, 1, 1, 1}; - context->OMSetBlendState(blendStates.BlendDisabled(), blendFactor, 0xFFFFFFFF); - context->OMSetDepthStencilState(depthStencilStates.DepthEnabled(), 0); - context->RSSetState(rasterizerStates.BackFaceCull()); - - ID3D11SamplerState* sampStates[] = { - samplerStates.Anisotropic(), - evsmSampler, - samplerStates.LinearClamp(), - samplerStates.ReversedShadowMapPCF(), - }; - - context->PSSetSamplers(0, ArraySize_(sampStates), sampStates); - - // Set constant buffers - meshVSConstants.Data.World = Float4x4(); - meshVSConstants.Data.View = Float4x4::Transpose(camera.ViewMatrix()); - meshVSConstants.Data.WorldViewProjection = Float4x4::Transpose(camera.ViewProjectionMatrix()); - meshVSConstants.Data.PrevWorldViewProjection = Float4x4::Transpose(prevVP); - meshVSConstants.ApplyChanges(context); - meshVSConstants.SetVS(context, 0); - - meshPSConstants.Data.SunDirectionWS = AppSettings::SunDirection; - meshPSConstants.Data.SunIlluminance = AppSettings::SunIlluminance(); - meshPSConstants.Data.CosSunAngularRadius = std::cos(DegToRad(AppSettings::SunSize) / 2.0f); - meshPSConstants.Data.SinSunAngularRadius = std::sin(DegToRad(AppSettings::SunSize) / 2.0f); - meshPSConstants.Data.CameraPosWS = camera.Position(); - meshPSConstants.Data.OffsetScale = OffsetScale; - meshPSConstants.Data.PositiveExponent = PositiveExponent; - meshPSConstants.Data.NegativeExponent = NegativeExponent; - meshPSConstants.Data.LightBleedingReduction = LightBleedingReduction; - for(uint64 i = 0; i < ArraySize_(status.SGDirections); ++i) - meshPSConstants.Data.SGDirections[i] = Float4(status.SGDirections[i], 0.0f); - meshPSConstants.Data.SGSharpness = status.SGSharpness; - meshPSConstants.ApplyChanges(context); - meshPSConstants.SetPS(context, 0); - - // Set shaders - context->DSSetShader(nullptr, nullptr, 0); - context->HSSetShader(nullptr, nullptr, 0); - context->GSSetShader(nullptr, nullptr, 0); - context->VSSetShader(meshVS, nullptr, 0); - context->PSSetShader(meshPS, nullptr, 0); - - // Draw all meshes - for(uint64 meshIdx = 0; meshIdx < sceneModel->Meshes().size(); ++meshIdx) - { - const Mesh& mesh = sceneModel->Meshes()[meshIdx]; - - // Set the vertices and indices - ID3D11Buffer* vertexBuffers[1] = { mesh.VertexBuffer() }; - UINT vertexStrides[1] = { mesh.VertexStride() }; - UINT offsets[1] = { 0 }; - context->IASetVertexBuffers(0, 1, vertexBuffers, vertexStrides, offsets); - context->IASetIndexBuffer(mesh.IndexBuffer(), mesh.IndexBufferFormat(), 0); - context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - - // Set the input layout - context->IASetInputLayout(meshInputLayouts[meshIdx]); - - // Draw all parts - for(uint64 partIdx = 0; partIdx < mesh.MeshParts().size(); ++partIdx) - { - const MeshPart& part = mesh.MeshParts()[partIdx]; - const MeshMaterial& material = sceneModel->Materials()[part.MaterialIdx]; - - // Set the textures - ID3D11ShaderResourceView* psTextures[] = - { - material.DiffuseMap, - material.NormalMap, - material.RoughnessMap, - material.MetallicMap, - sunVSM.SRView, - status.LightMap, - areaLightShadowMap.SRView, - shSpecularLookupA, - shSpecularLookupB, - }; - - context->PSSetShaderResources(0, ArraySize_(psTextures), psTextures); - context->DrawIndexed(part.IndexCount, part.IndexStart, 0); - } - } - - ID3D11ShaderResourceView* nullSRVs[10] = { NULL }; - context->PSSetShaderResources(0, ArraySize_(nullSRVs), nullSRVs); -} - -// Renders all meshes using depth-only rendering -void MeshRenderer::RenderDepth(ID3D11DeviceContext* context, const Camera& camera, bool noZClip, bool flippedZRange) -{ - PIXEvent event(L"Mesh Depth Rendering"); - - // Set states - float blendFactor[4] = {1, 1, 1, 1}; - context->OMSetBlendState(blendStates.ColorWriteDisabled(), blendFactor, 0xFFFFFFFF); - context->OMSetDepthStencilState(flippedZRange ? depthStencilStates.ReverseDepthWriteEnabled() - : depthStencilStates.DepthWriteEnabled(), 0); - - if(noZClip) - context->RSSetState(noZClipRSState); - else - context->RSSetState(rasterizerStates.BackFaceCull()); - - // Set constant buffers - meshVSConstants.Data.World = Float4x4(); - meshVSConstants.Data.View = Float4x4::Transpose(camera.ViewMatrix()); - meshVSConstants.Data.WorldViewProjection = Float4x4::Transpose(camera.ViewProjectionMatrix()); - meshVSConstants.ApplyChanges(context); - meshVSConstants.SetVS(context, 0); - - // Set shaders - context->VSSetShader(meshDepthVS , nullptr, 0); - context->PSSetShader(nullptr, nullptr, 0); - context->GSSetShader(nullptr, nullptr, 0); - context->DSSetShader(nullptr, nullptr, 0); - context->HSSetShader(nullptr, nullptr, 0); - - for(uint32 meshIdx = 0; meshIdx < sceneModel->Meshes().size(); ++meshIdx) - { - const Mesh& mesh = sceneModel->Meshes()[meshIdx]; - - // Set the vertices and indices - ID3D11Buffer* vertexBuffers[1] = { mesh.VertexBuffer() }; - UINT vertexStrides[1] = { mesh.VertexStride() }; - UINT offsets[1] = { 0 }; - context->IASetVertexBuffers(0, 1, vertexBuffers, vertexStrides, offsets); - context->IASetIndexBuffer(mesh.IndexBuffer(), mesh.IndexBufferFormat(), 0); - context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - - // Set the input layout - context->IASetInputLayout(meshDepthInputLayouts[meshIdx]); - - // Draw all parts - for(uint64 partIdx = 0; partIdx < mesh.MeshParts().size(); ++partIdx) - { - const MeshPart& part = mesh.MeshParts()[partIdx]; - context->DrawIndexed(part.IndexCount, part.IndexStart, 0); - } - } -} - -// Renders meshes using cascaded shadow mapping -void MeshRenderer::RenderSunShadowMap(ID3D11DeviceContext* context, const Camera& camera) -{ - PIXEvent event(L"Sun Shadow Map Rendering"); - - const float MinDistance = reductionDepth.x; - const float MaxDistance = reductionDepth.y; - - // Compute the split distances based on the partitioning mode - float CascadeSplits[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; - - { - float lambda = 1.0f; - - float nearClip = camera.NearClip(); - float farClip = camera.FarClip(); - float clipRange = farClip - nearClip; - - float minZ = nearClip + MinDistance * clipRange; - float maxZ = nearClip + MaxDistance * clipRange; - - float range = maxZ - minZ; - float ratio = maxZ / minZ; - - for(uint32 i = 0; i < NumCascades; ++i) - { - float p = (i + 1) / static_cast(NumCascades); - float log = minZ * std::pow(ratio, p); - float uniform = minZ + range * p; - float d = lambda * (log - uniform) + uniform; - CascadeSplits[i] = (d - nearClip) / clipRange; - } - } - - Float3 c0Extents; - Float4x4 c0Matrix; - - const Float3 lightDir = AppSettings::SunDirection; - - // Render the meshes to each cascade - for(uint32 cascadeIdx = 0; cascadeIdx < NumCascades; ++cascadeIdx) - { - PIXEvent cascadeEvent((L"Rendering Shadow Map Cascade " + ToString(cascadeIdx)).c_str()); - - // Set the viewport - SetViewport(context, ShadowMapSize, ShadowMapSize); - - // Set the shadow map as the depth target - ID3D11DepthStencilView* dsv = sunShadowDepthMap.DSView; - ID3D11RenderTargetView* nullRenderTargets[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = { NULL }; - context->OMSetRenderTargets(D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT, nullRenderTargets, dsv); - context->ClearDepthStencilView(dsv, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 1.0f, 0); - - // Get the 8 points of the view frustum in world space - XMVECTOR frustumCornersWS[8] = - { - XMVectorSet(-1.0f, 1.0f, 0.0f, 1.0f), - XMVectorSet( 1.0f, 1.0f, 0.0f, 1.0f), - XMVectorSet( 1.0f, -1.0f, 0.0f, 1.0f), - XMVectorSet(-1.0f, -1.0f, 0.0f, 1.0f), - XMVectorSet(-1.0f, 1.0f, 1.0f, 1.0f), - XMVectorSet( 1.0f, 1.0f, 1.0f, 1.0f), - XMVectorSet( 1.0f, -1.0f, 1.0f, 1.0f), - XMVectorSet(-1.0f, -1.0f, 1.0f, 1.0f), - }; - - float prevSplitDist = cascadeIdx == 0 ? MinDistance : CascadeSplits[cascadeIdx - 1]; - float splitDist = CascadeSplits[cascadeIdx]; - - XMVECTOR det; - XMMATRIX invViewProj = XMMatrixInverse(&det, camera.ViewProjectionMatrix().ToSIMD()); - for(uint32 i = 0; i < 8; ++i) - frustumCornersWS[i] = XMVector3TransformCoord(frustumCornersWS[i], invViewProj); - - // Get the corners of the current cascade slice of the view frustum - for(uint32 i = 0; i < 4; ++i) - { - XMVECTOR cornerRay = XMVectorSubtract(frustumCornersWS[i + 4], frustumCornersWS[i]); - XMVECTOR nearCornerRay = XMVectorScale(cornerRay, prevSplitDist); - XMVECTOR farCornerRay = XMVectorScale(cornerRay, splitDist); - frustumCornersWS[i + 4] = XMVectorAdd(frustumCornersWS[i], farCornerRay); - frustumCornersWS[i] = XMVectorAdd(frustumCornersWS[i], nearCornerRay); - } - - // Calculate the centroid of the view frustum slice - XMVECTOR frustumCenterVec = XMVectorZero(); - for(uint32 i = 0; i < 8; ++i) - frustumCenterVec = XMVectorAdd(frustumCenterVec, frustumCornersWS[i]); - frustumCenterVec = XMVectorScale(frustumCenterVec, 1.0f / 8.0f); - Float3 frustumCenter = frustumCenterVec; - - // Pick the up vector to use for the light camera - Float3 upDir = camera.Right(); - - Float3 minExtents; - Float3 maxExtents; - - { - // Create a temporary view matrix for the light - Float3 lightCameraPos = frustumCenter; - Float3 lookAt = frustumCenter - lightDir; - XMMATRIX lightView = XMMatrixLookAtLH(lightCameraPos.ToSIMD(), lookAt.ToSIMD(), upDir.ToSIMD()); - - // Calculate an AABB around the frustum corners - XMVECTOR mins = XMVectorSet(REAL_MAX, REAL_MAX, REAL_MAX, REAL_MAX); - XMVECTOR maxes = XMVectorSet(-REAL_MAX, -REAL_MAX, -REAL_MAX, -REAL_MAX); - for(uint32 i = 0; i < 8; ++i) - { - XMVECTOR corner = XMVector3TransformCoord(frustumCornersWS[i], lightView); - mins = XMVectorMin(mins, corner); - maxes = XMVectorMax(maxes, corner); - } - - minExtents = mins; - maxExtents = maxes; - } - - // Adjust the min/max to accommodate the filtering size - float scale = (ShadowMapSize + FilterSize) / static_cast(ShadowMapSize); - minExtents.x *= scale; - minExtents.y *= scale; - maxExtents.x *= scale; - maxExtents.y *= scale; - - Float3 cascadeExtents = maxExtents - minExtents; - - // Get position of the shadow camera - Float3 shadowCameraPos = frustumCenter + lightDir * -minExtents.z; - - // Come up with a new orthographic camera for the shadow caster - OrthographicCamera shadowCamera(minExtents.x, minExtents.y, maxExtents.x, - maxExtents.y, 0.0f, cascadeExtents.z); - shadowCamera.SetLookAt(shadowCameraPos, frustumCenter, upDir); - - // Draw the mesh with depth only, using the new shadow camera - RenderDepth(context, shadowCamera, true, false); - - // Apply the scale/offset matrix, which transforms from [-1,1] - // post-projection space to [0,1] UV space - XMMATRIX texScaleBias; - texScaleBias.r[0] = XMVectorSet(0.5f, 0.0f, 0.0f, 0.0f); - texScaleBias.r[1] = XMVectorSet(0.0f, -0.5f, 0.0f, 0.0f); - texScaleBias.r[2] = XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f); - texScaleBias.r[3] = XMVectorSet(0.5f, 0.5f, 0.0f, 1.0f); - XMMATRIX shadowMatrix = shadowCamera.ViewProjectionMatrix().ToSIMD(); - shadowMatrix = XMMatrixMultiply(shadowMatrix, texScaleBias); - - // Store the split distance in terms of view space depth - const float clipDist = camera.FarClip() - camera.NearClip(); - meshPSConstants.Data.CascadeSplits[cascadeIdx] = camera.NearClip() + splitDist * clipDist; - - if(cascadeIdx == 0) - { - c0Extents = cascadeExtents; - c0Matrix = shadowMatrix; - meshPSConstants.Data.ShadowMatrix = XMMatrixTranspose(shadowMatrix); - meshPSConstants.Data.CascadeOffsets[0] = Float4(0.0f, 0.0f, 0.0f, 0.0f); - meshPSConstants.Data.CascadeScales[0] = Float4(1.0f, 1.0f, 1.0f, 1.0f); - } - else - { - // Calculate the position of the lower corner of the cascade partition, in the UV space - // of the first cascade partition - Float4x4 invCascadeMat = Float4x4::Invert(shadowMatrix); - Float3 cascadeCorner = Float3::Transform(Float3(0.0f, 0.0f, 0.0f), invCascadeMat); - cascadeCorner = Float3::Transform(cascadeCorner, c0Matrix); - - // Do the same for the upper corner - Float3 otherCorner = Float3::Transform(Float3(1.0f, 1.0f, 1.0f), invCascadeMat); - otherCorner = Float3::Transform(otherCorner, c0Matrix); - - // Calculate the scale and offset - Float3 cascadeScale = Float3(1.0f, 1.0f, 1.f) / (otherCorner - cascadeCorner); - meshPSConstants.Data.CascadeOffsets[cascadeIdx] = Float4(-cascadeCorner, 0.0f); - meshPSConstants.Data.CascadeScales[cascadeIdx] = Float4(cascadeScale, 1.0f); - } - - ConvertToEVSM(context, cascadeIdx, meshPSConstants.Data.CascadeScales[cascadeIdx].To3D()); - } -} - -// Renders an omni-directional shadow map for the spherical area light -void MeshRenderer::RenderAreaLightShadowMap(ID3D11DeviceContext* context, const Camera& camera) -{ - PIXEvent event(L"Area Light Shadow Map Rendering"); - - const uint32 sMapSize = areaLightShadowMap.Width; - const Float3 areaLightPos = Float3(AppSettings::AreaLightX, AppSettings::AreaLightY, AppSettings::AreaLightZ); - const float nearClip = AppSettings::AreaLightSize; - - for(uint64 face = 0; face < 6; ++face) - { - PIXEvent faceEvent(L"Area Light Shadow Map Face " + ToString(face)); - - // Set the viewport - SetViewport(context, sMapSize, sMapSize); - - // Set the shadow map as the depth target - ID3D11DepthStencilView* dsv = areaLightShadowMap.ArraySlices[face]; - ID3D11RenderTargetView* nullRenderTargets[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = { NULL }; - context->OMSetRenderTargets(D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT, nullRenderTargets, dsv); - context->ClearDepthStencilView(dsv, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 0.0f, 0); - - PerspectiveCamera shadowCamera(1.0f, Pi_2, nearClip, nearClip + 1.0f); - - // Set up a infinite reverse projection - Float4x4 projection; - projection._33 = 0.0f; - projection._43 = nearClip; - projection._34 = 1.0f; - projection._44 = 0.0f; - shadowCamera.SetProjection(projection); - - static const Float3 LookAtDirs[6] = - { - Float3(1.0f, 0.0f, 0.0f), Float3(-1.0f, 0.0f, 0.0f), - Float3(0.0f, 1.0f, 0.0f), Float3(0.0f, -1.0f, 0.0f), - Float3(0.0f, 0.0f, 1.0f), Float3(0.0f, 0.0f, -1.0f) - }; - - static const Float3 UpDirs[6] = { - Float3(0.0f, 1.0f, 0.0f), Float3(0.0f, 1.0f, 0.0f), - Float3(0.0f, 0.0f, -1.0f), Float3(0.0f, 0.0f, 1.0f), - Float3(0.0f, 1.0f, 0.0f), Float3(0.0f, 1.0f, 0.0f), - }; - - shadowCamera.SetLookAt(areaLightPos, areaLightPos + LookAtDirs[face], UpDirs[face]); - - RenderDepth(context, shadowCamera, false, true); - } -} - -// Renders the area light -void MeshRenderer::RenderAreaLight(ID3D11DeviceContext* context, const Camera& camera) -{ - PIXEvent event(L"Area Light Rendering"); - - // Set states - float blendFactor[4] = {1, 1, 1, 1}; - context->OMSetBlendState(blendStates.BlendDisabled(), blendFactor, 0xFFFFFFFF); - context->OMSetDepthStencilState(depthStencilStates.DepthWriteEnabled(), 0); - context->RSSetState(rasterizerStates.NoCull()); - - // Set constant buffers - areaLightConstants.Data.ViewProjection = Float4x4::Transpose(camera.ViewProjectionMatrix()); - areaLightConstants.Data.PrevViewProjection = Float4x4::Transpose(prevVP); - areaLightConstants.ApplyChanges(context); - areaLightConstants.SetVS(context, 0); - areaLightConstants.SetPS(context, 0); - - // Set shaders - context->DSSetShader(nullptr, nullptr, 0); - context->HSSetShader(nullptr, nullptr, 0); - context->GSSetShader(nullptr, nullptr, 0); - context->VSSetShader(areaLightVS , nullptr, 0); - context->PSSetShader(areaLightPS, nullptr, 0); - - // Draw the visualizer sphere - ID3D11Buffer* vertexBuffers[1] = { areaLightVB }; - uint32 vertexStrides[1] = { sizeof(Float3) }; - uint32 offsets[1] = { 0 }; - context->IASetVertexBuffers(0, 1, vertexBuffers, vertexStrides, offsets); - context->IASetIndexBuffer(areaLightIB, DXGI_FORMAT_R32_UINT, 0); - context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - context->IASetInputLayout(areaLightInputLayout); - context->DrawIndexedInstanced(uint32(numAreaLightIndices), 1, 0, 0, 0); -} - -// Renders the bake data visualizer -void MeshRenderer::RenderBakeDataVisualizer(ID3D11DeviceContext* context, const Camera& camera, const MeshBakerStatus& status) -{ - PIXEvent event(L"Bake Data Visualizer"); - - // Set states - float blendFactor[4] = {1, 1, 1, 1}; - context->OMSetBlendState(blendStates.BlendDisabled(), blendFactor, 0xFFFFFFFF); - context->OMSetDepthStencilState(depthStencilStates.DepthWriteEnabled(), 0); - context->RSSetState(rasterizerStates.NoCull()); - - // Set constant buffers - visualizerConstants.Data.ViewProjection = Float4x4::Transpose(camera.ViewProjectionMatrix()); - for(uint64 i = 0; i < ArraySize_(status.SGDirections); ++i) - visualizerConstants.Data.SGDirections[i] = Float4(status.SGDirections[i], 0.0f); - visualizerConstants.Data.SGSharpness = status.SGSharpness; - visualizerConstants.ApplyChanges(context); - visualizerConstants.SetVS(context, 0); - visualizerConstants.SetPS(context, 0); - - // Set shaders - context->DSSetShader(nullptr, nullptr, 0); - context->HSSetShader(nullptr, nullptr, 0); - context->GSSetShader(nullptr, nullptr, 0); - context->VSSetShader(visualizerVS , nullptr, 0); - context->PSSetShader(visualizerPS, nullptr, 0); - - ID3D11ShaderResourceView* vsSrvs[] = { status.BakePoints }; - context->VSSetShaderResources(0, ArraySize_(vsSrvs), vsSrvs); - - ID3D11ShaderResourceView* psSrvs[1] = { status.LightMap }; - context->PSSetShaderResources(0, 1, psSrvs); - - // Draw the visualizer hemispheres for all sample points - ID3D11Buffer* vertexBuffers[1] = { hemisphereVB }; - uint32 vertexStrides[1] = { sizeof(Float3) }; - uint32 offsets[1] = { 0 }; - context->IASetVertexBuffers(0, 1, vertexBuffers, vertexStrides, offsets); - context->IASetIndexBuffer(hemisphereIB, DXGI_FORMAT_R32_UINT, 0); - context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - context->IASetInputLayout(visualizerInputLayout); - - // Draw - context->DrawIndexedInstanced(uint32(numHemisphereIndices), uint32(status.NumBakePoints), 0, 0, 0); - - ID3D11ShaderResourceView* nullSRVs[] = { nullptr }; - context->VSSetShaderResources(0, 1, nullSRVs); - context->PSSetShaderResources(0, 1, nullSRVs); +//================================================================================================= +// +// Baking Lab +// by MJP and David Neubelt +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +#include + +#include "MeshRenderer.h" + +#include +#include +#include +#include + +#include "AppSettings.h" +#include "SharedConstants.h" +#include "MeshBaker.h" + +// Constants +static const float ShadowNearClip = 1.0f; +static const float FilterSize = 7.0f; +static const uint32 SampleRadius = 3; +static const float OffsetScale = 0.0f; +static const float LightBleedingReduction = 0.10f; +static const float PositiveExponent = 40.0f; +static const float NegativeExponent = 8.0f; +static const uint32 ShadowMapSize = 1024; +static const uint32 ShadowMSAASamples = 4; +static const uint32 ShadowAnisotropy = 16; +static const bool EnableShadowMips = true; + +static void GenerateHemisphere(uint64 NumUSlices, uint64 NumVSlices, ID3D11Device* device, + ID3D11BufferPtr& vtxBuffer, ID3D11BufferPtr& idxBuffer, uint64& numIndices) +{ + Assert_(NumUSlices >= 3); + Assert_(NumVSlices >= 2); + + std::vector hemisphereVerts; + + // Add the vert at the top + hemisphereVerts.push_back(Float3(0.0f, 0.0f, 1.0f)); + + // Add the rings + for(uint64 v = 0; v < NumVSlices; ++v) + { + for(uint64 u = 0; u < NumUSlices; ++u) + { + const float theta = ((v + 1.0f) / NumVSlices) * Pi_2; + const float phi = (float(u) / NumUSlices) * Pi2; + + Float3 pos; + pos.x = std::sin(theta) * std::cos(phi); + pos.y = std::sin(theta) * std::sin(phi); + pos.z = std::cos(theta); + + hemisphereVerts.push_back(pos); + } + } + + Assert_(hemisphereVerts.size() <= UINT32_MAX); + + // Add the top ring of triangles + std::vector hemisphereIndices; + for(uint32 u = 0; u < NumUSlices; ++u) + { + hemisphereIndices.push_back(0); + hemisphereIndices.push_back(u + 1); + + if(u < NumUSlices - 1) + hemisphereIndices.push_back(u + 2); + else + hemisphereIndices.push_back(1); + } + + // Add the rest of the rings + uint32 prevRowStart = 1; + uint32 currRowStart = uint32(NumUSlices + 1); + for(uint32 v = 1; v < NumVSlices; ++v) + { + for(uint32 u = 0; u < NumUSlices; ++u) + { + uint32 nextBottom = currRowStart + u + 1; + uint32 nextTop = prevRowStart + u + 1; + if(u == NumUSlices - 1) + { + nextBottom = currRowStart; + nextTop = prevRowStart; + } + + hemisphereIndices.push_back(prevRowStart + u); + hemisphereIndices.push_back(currRowStart + u); + hemisphereIndices.push_back(nextBottom); + hemisphereIndices.push_back(nextBottom); + hemisphereIndices.push_back(nextTop); + hemisphereIndices.push_back(prevRowStart + u); + } + + prevRowStart = currRowStart; + currRowStart += uint32(NumUSlices); + } + + numIndices = hemisphereIndices.size(); + + D3D11_BUFFER_DESC bufferDesc; + bufferDesc.ByteWidth = sizeof(Float3) * uint32(hemisphereVerts.size()); + bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bufferDesc.CPUAccessFlags = 0; + bufferDesc.MiscFlags = 0; + bufferDesc.StructureByteStride = 0; + bufferDesc.Usage = D3D11_USAGE_IMMUTABLE; + + D3D11_SUBRESOURCE_DATA initData; + initData.pSysMem = hemisphereVerts.data(); + initData.SysMemPitch = 0; + initData.SysMemSlicePitch = 0; + DXCall(device->CreateBuffer(&bufferDesc, &initData, &vtxBuffer)); + + bufferDesc.ByteWidth = sizeof(uint32) * uint32(hemisphereIndices.size()); + bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; + initData.pSysMem = hemisphereIndices.data(); + DXCall(device->CreateBuffer(&bufferDesc, &initData, &idxBuffer)); +} + +static void GenerateSphere(uint64 NumUSlices, uint64 NumVSlices, ID3D11Device* device, + ID3D11BufferPtr& vtxBuffer, ID3D11BufferPtr& idxBuffer, uint64& numIndices) +{ + Assert_(NumUSlices >= 3); + Assert_(NumVSlices >= 3); + + std::vector sphereVerts; + + // Add the vert at the top + sphereVerts.push_back(Float3(0.0f, 0.0f, 1.0f)); + + // Add the rings + for(uint64 v = 0; v < NumVSlices - 1; ++v) + { + for(uint64 u = 0; u < NumUSlices; ++u) + { + const float theta = ((v + 1.0f) / NumVSlices) * Pi; + const float phi = (float(u) / NumUSlices) * Pi2; + + Float3 pos; + pos.x = std::sin(theta) * std::cos(phi); + pos.y = std::sin(theta) * std::sin(phi); + pos.z = std::cos(theta); + + sphereVerts.push_back(pos); + } + } + + // Add the vert at the bottom + const uint32 lastVertIdx = uint32(sphereVerts.size()); + sphereVerts.push_back(Float3(0.0f, 0.0f, -1.0f)); + + Assert_(sphereVerts.size() <= UINT32_MAX); + + // Add the top ring of triangles + std::vector sphereIndices; + for(uint32 u = 0; u < NumUSlices; ++u) + { + sphereIndices.push_back(0); + sphereIndices.push_back(u + 1); + + if(u < NumUSlices - 1) + sphereIndices.push_back(u + 2); + else + sphereIndices.push_back(1); + } + + // Add the rest of the rings + uint32 prevRowStart = 1; + uint32 currRowStart = uint32(NumUSlices + 1); + for(uint32 v = 1; v < NumVSlices - 1; ++v) + { + for(uint32 u = 0; u < NumUSlices; ++u) + { + uint32 nextBottom = currRowStart + u + 1; + uint32 nextTop = prevRowStart + u + 1; + if(u == NumUSlices - 1) + { + nextBottom = currRowStart; + nextTop = prevRowStart; + } + + sphereIndices.push_back(prevRowStart + u); + sphereIndices.push_back(currRowStart + u); + sphereIndices.push_back(nextBottom); + sphereIndices.push_back(nextBottom); + sphereIndices.push_back(nextTop); + sphereIndices.push_back(prevRowStart + u); + } + + prevRowStart = currRowStart; + currRowStart += uint32(NumUSlices); + } + + // Add the last ring at the bottom + const uint32 lastRingStart = uint32(lastVertIdx - NumUSlices); + for(uint32 u = 0; u < NumUSlices; ++u) + { + sphereIndices.push_back(lastVertIdx); + sphereIndices.push_back(lastRingStart + u); + + if(u < NumUSlices - 1) + sphereIndices.push_back(lastRingStart + u + 1); + else + sphereIndices.push_back(lastRingStart); + } + + numIndices = sphereIndices.size(); + + D3D11_BUFFER_DESC bufferDesc; + bufferDesc.ByteWidth = sizeof(Float3) * uint32(sphereVerts.size()); + bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bufferDesc.CPUAccessFlags = 0; + bufferDesc.MiscFlags = 0; + bufferDesc.StructureByteStride = 0; + bufferDesc.Usage = D3D11_USAGE_IMMUTABLE; + + D3D11_SUBRESOURCE_DATA initData; + initData.pSysMem = sphereVerts.data(); + initData.SysMemPitch = 0; + initData.SysMemSlicePitch = 0; + DXCall(device->CreateBuffer(&bufferDesc, &initData, &vtxBuffer)); + + bufferDesc.ByteWidth = sizeof(uint32) * uint32(sphereIndices.size()); + bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; + initData.pSysMem = sphereIndices.data(); + DXCall(device->CreateBuffer(&bufferDesc, &initData, &idxBuffer)); +} + +const uint32 NumBoxVerts = 24; +const uint32 NumBoxIndices = 36; + +static void GenerateBox(ID3D11Device* device, ID3D11BufferPtr& vtxBuffer, ID3D11BufferPtr& idxBuffer) +{ + std::vector boxVerts(NumBoxVerts); + std::vector boxIndices(NumBoxIndices, 0); + + uint64 vIdx = 0; + + // Top + boxVerts[vIdx++] = Float3(-0.5f, 0.5f, 0.5f); + boxVerts[vIdx++] = Float3(0.5f, 0.5f, 0.5f); + boxVerts[vIdx++] = Float3(0.5f, 0.5f, -0.5f); + boxVerts[vIdx++] = Float3(-0.5f, 0.5f, -0.5f); + + // Bottom + boxVerts[vIdx++] = Float3(-0.5f, -0.5f, -0.5f); + boxVerts[vIdx++] = Float3(0.5f, -0.5f, -0.5f); + boxVerts[vIdx++] = Float3(0.5f, -0.5f, 0.5f); + boxVerts[vIdx++] = Float3(-0.5f, -0.5f, 0.5f); + + // Front + boxVerts[vIdx++] = Float3(-0.5f, 0.5f, -0.5f); + boxVerts[vIdx++] = Float3(0.5f, 0.5f, -0.5f); + boxVerts[vIdx++] = Float3(0.5f, -0.5f, -0.5f); + boxVerts[vIdx++] = Float3(-0.5f, -0.5f, -0.5f); + + // Back + boxVerts[vIdx++] = Float3(0.5f, 0.5f, 0.5f); + boxVerts[vIdx++] = Float3(-0.5f, 0.5f, 0.5f); + boxVerts[vIdx++] = Float3(-0.5f, -0.5f, 0.5f); + boxVerts[vIdx++] = Float3(0.5f, -0.5f, 0.5f); + + // Left + boxVerts[vIdx++] = Float3(-0.5f, 0.5f, 0.5f); + boxVerts[vIdx++] = Float3(-0.5f, 0.5f, -0.5f); + boxVerts[vIdx++] = Float3(-0.5f, -0.5f, -0.5f); + boxVerts[vIdx++] = Float3(-0.5f, -0.5f, 0.5f); + + // Right + boxVerts[vIdx++] = Float3(0.5f, 0.5f, -0.5f); + boxVerts[vIdx++] = Float3(0.5f, 0.5f, 0.5f); + boxVerts[vIdx++] = Float3(0.5f, -0.5f, 0.5f); + boxVerts[vIdx++] = Float3(0.5f, -0.5f, -0.5f); + + uint64 iIdx = 0; + + // Top + boxIndices[iIdx++] = 0; + boxIndices[iIdx++] = 1; + boxIndices[iIdx++] = 2; + boxIndices[iIdx++] = 2; + boxIndices[iIdx++] = 3; + boxIndices[iIdx++] = 0; + + // Bottom + boxIndices[iIdx++] = 4 + 0; + boxIndices[iIdx++] = 4 + 1; + boxIndices[iIdx++] = 4 + 2; + boxIndices[iIdx++] = 4 + 2; + boxIndices[iIdx++] = 4 + 3; + boxIndices[iIdx++] = 4 + 0; + + // Front + boxIndices[iIdx++] = 8 + 0; + boxIndices[iIdx++] = 8 + 1; + boxIndices[iIdx++] = 8 + 2; + boxIndices[iIdx++] = 8 + 2; + boxIndices[iIdx++] = 8 + 3; + boxIndices[iIdx++] = 8 + 0; + + // Back + boxIndices[iIdx++] = 12 + 0; + boxIndices[iIdx++] = 12 + 1; + boxIndices[iIdx++] = 12 + 2; + boxIndices[iIdx++] = 12 + 2; + boxIndices[iIdx++] = 12 + 3; + boxIndices[iIdx++] = 12 + 0; + + // Left + boxIndices[iIdx++] = 16 + 0; + boxIndices[iIdx++] = 16 + 1; + boxIndices[iIdx++] = 16 + 2; + boxIndices[iIdx++] = 16 + 2; + boxIndices[iIdx++] = 16 + 3; + boxIndices[iIdx++] = 16 + 0; + + // Right + boxIndices[iIdx++] = 20 + 0; + boxIndices[iIdx++] = 20 + 1; + boxIndices[iIdx++] = 20 + 2; + boxIndices[iIdx++] = 20 + 2; + boxIndices[iIdx++] = 20 + 3; + boxIndices[iIdx++] = 20 + 0; + + D3D11_BUFFER_DESC bufferDesc; + bufferDesc.ByteWidth = sizeof(Float3) * NumBoxVerts; + bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bufferDesc.CPUAccessFlags = 0; + bufferDesc.MiscFlags = 0; + bufferDesc.StructureByteStride = 0; + bufferDesc.Usage = D3D11_USAGE_IMMUTABLE; + + D3D11_SUBRESOURCE_DATA initData; + initData.pSysMem = boxVerts.data(); + initData.SysMemPitch = 0; + initData.SysMemSlicePitch = 0; + DXCall(device->CreateBuffer(&bufferDesc, &initData, &vtxBuffer)); + + bufferDesc.ByteWidth = sizeof(uint16) * NumBoxIndices; + bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; + initData.pSysMem = boxIndices.data(); + DXCall(device->CreateBuffer(&bufferDesc, &initData, &idxBuffer)); +} + +void MeshRenderer::LoadShaders() +{ + // Load the mesh shaders + meshDepthVS = CompileVSFromFile(device, L"DepthOnly.hlsl", "VS", "vs_5_0"); + { + CompileOptions opts; + opts.Add("ProbeRendering_", 0); + opts.Add("Voxelize_", 0); + meshVS = CompileVSFromFile(device, L"Mesh.hlsl", "VS", "vs_5_0", opts); + meshPS = CompilePSFromFile(device, L"Mesh.hlsl", "PS", "ps_5_0", opts); + + opts.Reset(); + opts.Add("ProbeRendering_", 1); + opts.Add("Voxelize_", 0); + meshPSProbes = CompilePSFromFile(device, L"Mesh.hlsl", "PS", "ps_5_0", opts); + + opts.Reset(); + opts.Add("ProbeRendering_", 0); + opts.Add("Voxelize_", 1); + meshVSVoxelize = CompileVSFromFile(device, L"Mesh.hlsl", "VS", "vs_5_0", opts); + meshPSVoxelize = CompilePSFromFile(device, L"Mesh.hlsl", "PS", "ps_5_0", opts); + } + + areaLightVS = CompileVSFromFile(device, L"AreaLight.hlsl", "VS", "vs_5_0"); + areaLightPS = CompilePSFromFile(device, L"AreaLight.hlsl", "PS", "ps_5_0"); + + visualizerVS = CompileVSFromFile(device, L"BakeDataVisualizer.hlsl", "VS", "vs_5_0"); + visualizerPS = CompilePSFromFile(device, L"BakeDataVisualizer.hlsl", "PS", "ps_5_0"); + + probeVisualizerVS = CompileVSFromFile(device, L"ProbeVisualizer.hlsl", "VS", "vs_5_0"); + probeVisualizerPS = CompilePSFromFile(device, L"ProbeVisualizer.hlsl", "PS", "ps_5_0"); + + voxelGeoVS = CompileVSFromFile(device, L"VoxelVisualizer.hlsl", "GeoVS", "vs_5_0"); + voxelGeoPS = CompilePSFromFile(device, L"VoxelVisualizer.hlsl", "GeoPS", "ps_5_0"); + + { + CompileOptions opts; + opts.Add("FirstMip_", 1); + + voxelRayMarchVS = CompileVSFromFile(device, L"VoxelVisualizer.hlsl", "RayMarchVS", "vs_5_0", opts); + voxelRayMarchFirstMipPS = CompilePSFromFile(device, L"VoxelVisualizer.hlsl", "RayMarchPS", "ps_5_0", opts); + + opts.Reset(); + opts.Add("FirstMip_", 0); + voxelRayMarchPS = CompilePSFromFile(device, L"VoxelVisualizer.hlsl", "RayMarchPS", "ps_5_0", opts); + } + + fullScreenVS = CompileVSFromFile(device, L"EVSMConvert.hlsl", "FullScreenVS"); + + CompileOptions opts; + opts.Add("MSAASamples_", ShadowMSAASamples); + evsmConvertPS = CompilePSFromFile(device, L"EVSMConvert.hlsl", "ConvertToEVSM", "ps_5_0", opts); + + opts.Reset(); + opts.Add("Horizontal_", 1); + opts.Add("Vertical_", 0); + opts.Add("SampleRadius_", SampleRadius); + evsmBlurH = CompilePSFromFile(device, L"EVSMConvert.hlsl", "BlurEVSM", "ps_5_0", opts); + + opts.Reset(); + opts.Add("Horizontal_", 0); + opts.Add("Vertical_", 1); + opts.Add("SampleRadius_", SampleRadius); + evsmBlurV = CompilePSFromFile(device, L"EVSMConvert.hlsl", "BlurEVSM", "ps_5_0", opts); + + opts.Reset(); + opts.Add("MSAA_", 0); + depthReductionInitialCS[0] = CompileCSFromFile(device, L"DepthReduction.hlsl", "DepthReductionInitialCS", "cs_5_0", opts); + + opts.Reset(); + opts.Add("MSAA_", 1); + depthReductionInitialCS[1] = CompileCSFromFile(device, L"DepthReduction.hlsl", "DepthReductionInitialCS", "cs_5_0", opts); + + depthReductionCS = CompileCSFromFile(device, L"DepthReduction.hlsl", "DepthReductionCS"); +} + +void MeshRenderer::CreateShadowMaps() +{ + // Create the shadow map as a texture atlas + sunShadowDepthMap.Initialize(device, ShadowMapSize, ShadowMapSize, DXGI_FORMAT_D24_UNORM_S8_UINT, true, + ShadowMSAASamples, 0, 1); + + DXGI_FORMAT smFmt = DXGI_FORMAT_R32G32B32A32_FLOAT; + uint32 numMips = EnableShadowMips ? 0 : 1; + sunVSM.Initialize(device, ShadowMapSize, ShadowMapSize, smFmt, numMips, 1, 0, + EnableShadowMips, false, NumCascades, false); + + tempVSM.Initialize(device, ShadowMapSize, ShadowMapSize, smFmt, 1, 1, 0, false, false, 1, false); + + areaLightShadowMap.Initialize(device, ShadowMapSize, ShadowMapSize, DXGI_FORMAT_D32_FLOAT, true, 1, 0, 6, true); +} + +// Loads resources +void MeshRenderer::Initialize(ID3D11Device* device, ID3D11DeviceContext* context, const Model* model) +{ + this->device = device; + + blendStates.Initialize(device); + rasterizerStates.Initialize(device); + depthStencilStates.Initialize(device); + samplerStates.Initialize(device); + + meshVSConstants.Initialize(device); + meshPSConstants.Initialize(device); + areaLightConstants.Initialize(device); + visualizerConstants.Initialize(device); + evsmConstants.Initialize(device); + reductionConstants.Initialize(device); + voxelVisualizerConstants.Initialize(device); + + shSpecularLookupA = LoadTexture(device, L"..\\Content\\Textures\\SHSpecularA.dds"); + shSpecularLookupB = LoadTexture(device, L"..\\Content\\Textures\\SHSpecularB.dds"); + + LoadShaders(); + + D3D11_RASTERIZER_DESC rsDesc = RasterizerStates::NoCullDesc(); + rsDesc.DepthClipEnable = false; + DXCall(device->CreateRasterizerState(&rsDesc, &noZClipRSState)); + + D3D11_SAMPLER_DESC sampDesc = SamplerStates::AnisotropicDesc(); + sampDesc.MaxAnisotropy = ShadowAnisotropy; + DXCall(device->CreateSamplerState(&sampDesc, &evsmSampler)); + + // Create the staging textures for reading back the reduced depth buffer + for(uint32 i = 0; i < ReadbackLatency; ++i) + reductionStagingTextures[i].Initialize(device, 1, 1, DXGI_FORMAT_R16G16_UNORM); + + CreateShadowMaps(); + + GenerateHemisphere(16, 4, device, hemisphereVB, hemisphereIB, numHemisphereIndices); + + GenerateSphere(16, 8, device, sphereVB, sphereIB, numSphereIndices); + + GenerateBox(device, voxelVisualizerVB, voxelVisualizerIB); + + D3D11_INPUT_ELEMENT_DESC elements[1]; + elements[0].AlignedByteOffset = 0; + elements[0].Format = DXGI_FORMAT_R32G32B32_FLOAT; + elements[0].InputSlot = 0; + elements[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; + elements[0].InstanceDataStepRate = 0; + elements[0].SemanticName = "POSITION"; + elements[0].SemanticIndex = 0; + + DXCall(device->CreateInputLayout(elements, 1, visualizerVS->ByteCode->GetBufferPointer(), + visualizerVS->ByteCode->GetBufferSize(), &visualizerInputLayout)); + + DXCall(device->CreateInputLayout(elements, 1, probeVisualizerVS->ByteCode->GetBufferPointer(), + probeVisualizerVS->ByteCode->GetBufferSize(), &probeVisualizerInputLayout)); + + DXCall(device->CreateInputLayout(elements, 1, areaLightVS->ByteCode->GetBufferPointer(), + areaLightVS->ByteCode->GetBufferSize(), &areaLightInputLayout)); + + DXCall(device->CreateInputLayout(elements, 1, voxelGeoVS->ByteCode->GetBufferPointer(), + voxelGeoVS->ByteCode->GetBufferSize(), &voxelGeoIL)); + + DXCall(device->CreateInputLayout(elements, 1, voxelRayMarchVS->ByteCode->GetBufferPointer(), + voxelRayMarchVS->ByteCode->GetBufferSize(), &voxelRayMarchIL)); + + SetModel(model); +} + +void MeshRenderer::SetModel(const Model* model) +{ + Assert_(model != nullptr); + sceneModel = model; + + meshInputLayouts.clear(); + meshDepthInputLayouts.clear(); + + for(uint64 i = 0; i < sceneModel->Meshes().size(); ++i) + { + // Generate input layouts for the scene meshes + const Mesh& mesh = sceneModel->Meshes()[i]; + ID3D11InputLayoutPtr inputLayout; + DXCall(device->CreateInputLayout(mesh.InputElements(), mesh.NumInputElements(), + meshVS->ByteCode->GetBufferPointer(), meshVS->ByteCode->GetBufferSize(), &inputLayout)); + meshInputLayouts.push_back(inputLayout); + + DXCall(device->CreateInputLayout(mesh.InputElements(), mesh.NumInputElements(), + meshDepthVS->ByteCode->GetBufferPointer(), meshDepthVS->ByteCode->GetBufferSize(), &inputLayout)); + meshDepthInputLayouts.push_back(inputLayout); + } +} + +void MeshRenderer::Update(const Camera& camera, Float2 jitterOffset) +{ + prevVP = currVP; + currVP = camera.ViewProjectionMatrix(); + if(firstFrame) + { + prevVP = currVP; + firstFrame = false; + } + + meshPSConstants.Data.JitterOffset = jitterOffset; + areaLightConstants.Data.JitterOffset = jitterOffset; +} + +void MeshRenderer::OnResize(uint32 width, uint32 height) +{ + depthReductionTargets.clear(); + + uint32 w = width; + uint32 h = height; + + while(w > 1 || h > 1) + { + w = DispatchSize(ReductionTGSize, w); + h = DispatchSize(ReductionTGSize, h); + + RenderTarget2D rt; + rt.Initialize(device, w, h, DXGI_FORMAT_R16G16_UNORM, 1, 1, 0, false, true); + depthReductionTargets.push_back(rt); + } + + meshPSConstants.Data.RTSize.x = float(width); + meshPSConstants.Data.RTSize.y = float(height); + + areaLightConstants.Data.RTSize = meshPSConstants.Data.RTSize; +} + +void MeshRenderer::ReduceDepth(ID3D11DeviceContext* context, const DepthStencilBuffer& depthTarget, + const Camera& camera) +{ + PIXEvent event(L"Depth Reduction"); + + reductionConstants.Data.Projection = Float4x4::Transpose(camera.ProjectionMatrix()); + reductionConstants.Data.NearClip = camera.NearClip(); + reductionConstants.Data.FarClip = camera.FarClip(); + reductionConstants.Data.TextureSize = Uint2(depthTarget.Width, depthTarget.Height); + reductionConstants.Data.NumSamples = depthTarget.MultiSamples; + reductionConstants.ApplyChanges(context); + reductionConstants.SetCS(context, 0); + + ID3D11RenderTargetView* rtvs[1] = { nullptr }; + context->OMSetRenderTargets(1, rtvs, nullptr); + + ID3D11UnorderedAccessView* uavs[1] = { depthReductionTargets[0].UAView }; + context->CSSetUnorderedAccessViews(0, 1, uavs, nullptr); + + ID3D11ShaderResourceView* srvs[1] = { depthTarget.SRView }; + context->CSSetShaderResources(0, 1, srvs); + + const bool msaa = depthTarget.MultiSamples > 1; + + ID3D11ComputeShader* shader = depthReductionInitialCS[msaa ? 1 : 0]; + context->CSSetShader(shader, nullptr, 0); + + uint32 dispatchX = depthReductionTargets[0].Width; + uint32 dispatchY = depthReductionTargets[0].Height; + context->Dispatch(dispatchX, dispatchY, 1); + + uavs[0] = nullptr; + context->CSSetUnorderedAccessViews(0, 1, uavs, nullptr); + + srvs[0] = nullptr; + context->CSSetShaderResources(0, 1, srvs); + + context->CSSetShader(depthReductionCS, nullptr, 0); + + for(uint32 i = 1; i < depthReductionTargets.size(); ++i) + { + RenderTarget2D& srcTexture = depthReductionTargets[i - 1]; + reductionConstants.Data.TextureSize.x = srcTexture.Width; + reductionConstants.Data.TextureSize.y = srcTexture.Height; + reductionConstants.Data.NumSamples = srcTexture.MultiSamples; + reductionConstants.ApplyChanges(context); + + uavs[0] = depthReductionTargets[i].UAView; + context->CSSetUnorderedAccessViews(0, 1, uavs, nullptr); + + srvs[0] = srcTexture.SRView; + context->CSSetShaderResources(0, 1, srvs); + + dispatchX = depthReductionTargets[i].Width; + dispatchY = depthReductionTargets[i].Height; + context->Dispatch(dispatchX, dispatchY, 1); + + uavs[0] = nullptr; + context->CSSetUnorderedAccessViews(0, 1, uavs, nullptr); + + srvs[0] = nullptr; + context->CSSetShaderResources(0, 1, srvs); + } + + // Copy to a staging texture + ID3D11Texture2D* lastTarget = depthReductionTargets[depthReductionTargets.size() - 1].Texture; + context->CopyResource(reductionStagingTextures[currFrame % ReadbackLatency].Texture, lastTarget); + + ++currFrame; + + if(currFrame >= ReadbackLatency) + { + StagingTexture2D& stagingTexture = reductionStagingTextures[currFrame % ReadbackLatency]; + + uint32 pitch; + const uint16* texData = reinterpret_cast(stagingTexture.Map(context, 0, pitch)); + reductionDepth.x = texData[0] / static_cast(0xffff); + reductionDepth.y = texData[1] / static_cast(0xffff); + + stagingTexture.Unmap(context, 0); + } + else + { + reductionDepth = Float2(0.0f, 1.0f); + } +} + +// Convert to an EVSM map +void MeshRenderer::ConvertToEVSM(ID3D11DeviceContext* context, uint32 cascadeIdx, Float3 cascadeScale) +{ + PIXEvent event(L"EVSM Conversion"); + + float blendFactor[4] = {1, 1, 1, 1}; + context->OMSetBlendState(blendStates.BlendDisabled(), blendFactor, 0xFFFFFFFF); + context->RSSetState(rasterizerStates.NoCull()); + context->OMSetDepthStencilState(depthStencilStates.DepthDisabled(), 0); + ID3D11Buffer* vbs[1] = { nullptr }; + uint32 strides[1] = { 0 }; + uint32 offsets[1] = { 0 }; + context->IASetVertexBuffers(0, 1, vbs, strides, offsets); + context->IASetIndexBuffer(nullptr, DXGI_FORMAT_R32_UINT, 0); + context->IASetInputLayout(nullptr); + + SetViewport(context, sunVSM.Width, sunVSM.Height); + + evsmConstants.Data.PositiveExponent = PositiveExponent; + evsmConstants.Data.NegativeExponent = NegativeExponent; + evsmConstants.Data.CascadeScale = meshPSConstants.Data.CascadeScales[cascadeIdx].To3D(); + evsmConstants.Data.FilterSize = 1.0f; + evsmConstants.Data.ShadowMapSize.x = float(sunVSM.Width); + evsmConstants.Data.ShadowMapSize.y = float(sunVSM.Height); + evsmConstants.ApplyChanges(context); + evsmConstants.SetPS(context, 0); + + context->VSSetShader(fullScreenVS, nullptr, 0); + context->PSSetShader(evsmConvertPS, nullptr, 0); + + ID3D11RenderTargetView* rtvs[1] = { sunVSM.RTVArraySlices[cascadeIdx] }; + context->OMSetRenderTargets(1, rtvs, nullptr); + + ID3D11ShaderResourceView* srvs[1] = { sunShadowDepthMap.SRView }; + context->PSSetShaderResources(0, 1, srvs); + + context->Draw(3, 0); + + srvs[0] = nullptr; + context->PSSetShaderResources(0, 1, srvs); + + const float FilterSizeU = std::max(FilterSize * cascadeScale.x, 1.0f); + const float FilterSizeV = std::max(FilterSize * cascadeScale.y, 1.0f); + + if(FilterSizeU > 1.0f || FilterSizeV > 1.0f) + { + // Horizontal pass + evsmConstants.Data.FilterSize = FilterSizeU; + evsmConstants.ApplyChanges(context); + + uint32 sampleRadiusU = static_cast((FilterSizeU / 2) + 0.499f); + + rtvs[0] = tempVSM.RTView; + context->OMSetRenderTargets(1, rtvs, nullptr); + + srvs[0] = sunVSM.SRVArraySlices[cascadeIdx]; + context->PSSetShaderResources(0, 1, srvs); + + context->PSSetShader(evsmBlurH, nullptr, 0); + + context->Draw(3, 0); + + srvs[0] = nullptr; + context->PSSetShaderResources(0, 1, srvs); + + // Vertical pass + evsmConstants.Data.FilterSize = FilterSizeV; + evsmConstants.ApplyChanges(context); + + uint32 sampleRadiusV = static_cast((FilterSizeV / 2) + 0.499f); + + rtvs[0] = sunVSM.RTVArraySlices[cascadeIdx]; + context->OMSetRenderTargets(1, rtvs, nullptr); + + srvs[0] = tempVSM.SRView; + context->PSSetShaderResources(0, 1, srvs); + + context->PSSetShader(evsmBlurV, nullptr, 0); + + context->Draw(3, 0); + + srvs[0] = nullptr; + context->PSSetShaderResources(0, 1, srvs); + } + + if(EnableShadowMips && cascadeIdx == NumCascades - 1) + context->GenerateMips(sunVSM.SRView); +} + +// Renders all meshes in the model, with shadows +void MeshRenderer::RenderMainPass(ID3D11DeviceContext* context, const Camera& camera, const MeshBakerStatus& status, + bool32 probeRendering, bool voxelizing) +{ + Assert_(probeRendering == false || voxelizing == false); + + PIXEvent event(L"Mesh Rendering"); + + // Set states + float blendFactor[4] = {1, 1, 1, 1}; + context->OMSetBlendState(blendStates.BlendDisabled(), blendFactor, 0xFFFFFFFF); + context->OMSetDepthStencilState(depthStencilStates.DepthEnabled(), 0); + + if(voxelizing && 0) + context->RSSetState(rasterizerStates.NoCullConservative()); + else + context->RSSetState(rasterizerStates.NoCull()); + + ID3D11SamplerState* sampStates[] = { + samplerStates.Anisotropic(), + evsmSampler, + samplerStates.LinearClamp(), + samplerStates.ReversedShadowMapPCF(), + samplerStates.Point(), + samplerStates.LinearBorder(), + }; + + context->PSSetSamplers(0, ArraySize_(sampStates), sampStates); + + // Set constant buffers + meshVSConstants.Data.World = Float4x4(); + meshVSConstants.Data.View = Float4x4::Transpose(camera.ViewMatrix()); + meshVSConstants.Data.WorldViewProjection = Float4x4::Transpose(camera.ViewProjectionMatrix()); + meshVSConstants.Data.PrevWorldViewProjection = Float4x4::Transpose(prevVP); + meshVSConstants.ApplyChanges(context); + meshVSConstants.SetVS(context, 0); + meshVSConstants.SetPS(context, 0); + + meshPSConstants.Data.SunDirectionWS = AppSettings::SunDirection; + meshPSConstants.Data.SunIlluminance = AppSettings::SunIlluminance(); + meshPSConstants.Data.CosSunAngularRadius = std::cos(DegToRad(AppSettings::SunSize) / 2.0f); + meshPSConstants.Data.SinSunAngularRadius = std::sin(DegToRad(AppSettings::SunSize) / 2.0f); + meshPSConstants.Data.CameraPosWS = camera.Position(); + meshPSConstants.Data.OffsetScale = OffsetScale; + meshPSConstants.Data.PositiveExponent = PositiveExponent; + meshPSConstants.Data.NegativeExponent = NegativeExponent; + meshPSConstants.Data.LightBleedingReduction = LightBleedingReduction; + for(uint64 i = 0; i < ArraySize_(status.SGDirections); ++i) + meshPSConstants.Data.SGDirections[i] = Float4(status.SGDirections[i], 0.0f); + meshPSConstants.Data.SGSharpness = status.SGSharpness; + meshPSConstants.Data.SceneMinBounds = status.SceneMinBounds; + meshPSConstants.Data.SceneMaxBounds = status.SceneMaxBounds; + meshPSConstants.Data.SkySH = status.SkySH; + meshPSConstants.ApplyChanges(context); + meshPSConstants.SetVS(context, 1); + meshPSConstants.SetPS(context, 1); + + // Set shaders + context->DSSetShader(nullptr, nullptr, 0); + context->HSSetShader(nullptr, nullptr, 0); + context->GSSetShader(nullptr, nullptr, 0); + + + ID3D11VertexShader* vs = meshVS; + ID3D11PixelShader* ps = meshPS; + if(voxelizing) + { + ps = meshPSVoxelize; + vs = meshVSVoxelize; + } + else if(probeRendering) + { + vs = meshVS; + ps = meshPSProbes; + } + + context->VSSetShader(vs, nullptr, 0); + context->PSSetShader(ps, nullptr, 0); + + // Draw all meshes + for(uint64 meshIdx = 0; meshIdx < sceneModel->Meshes().size(); ++meshIdx) + { + const Mesh& mesh = sceneModel->Meshes()[meshIdx]; + + // Set the vertices and indices + ID3D11Buffer* vertexBuffers[1] = { mesh.VertexBuffer() }; + UINT vertexStrides[1] = { mesh.VertexStride() }; + UINT offsets[1] = { 0 }; + context->IASetVertexBuffers(0, 1, vertexBuffers, vertexStrides, offsets); + context->IASetIndexBuffer(mesh.IndexBuffer(), mesh.IndexBufferFormat(), 0); + context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + // Set the input layout + context->IASetInputLayout(meshInputLayouts[meshIdx]); + + // Draw all parts + for(uint64 partIdx = 0; partIdx < mesh.MeshParts().size(); ++partIdx) + { + const MeshPart& part = mesh.MeshParts()[partIdx]; + const MeshMaterial& material = sceneModel->Materials()[part.MaterialIdx]; + + // Set the textures + ID3D11ShaderResourceView* psTextures[] = + { + material.DiffuseMap, + material.NormalMap, + material.RoughnessMap, + material.MetallicMap, + sunVSM.SRView, + status.LightMap, + areaLightShadowMap.SRView, + shSpecularLookupA, + shSpecularLookupB, + status.ProbeIrradianceCubeMap, + status.ProbeDistanceCubeMap, + }; + + context->PSSetShaderResources(0, ArraySize_(psTextures), psTextures); + + uint32 offset = ArraySize_(psTextures); + context->PSSetShaderResources(offset, 1, &status.VoxelRadiance); + + offset += 1; + context->PSSetShaderResources(offset, ArraySize_(status.VoxelRadianceMips), status.VoxelRadianceMips); + + offset += ArraySize_(status.VoxelRadianceMips); + context->PSSetShaderResources(offset, ArraySize_(status.ProbeVolumeMaps), status.ProbeVolumeMaps); + + offset += ArraySize_(status.ProbeVolumeMaps); + context->PSSetShaderResources(offset, ArraySize_(status.ProbeDistanceVolumeMaps), status.ProbeDistanceVolumeMaps); + + context->DrawIndexed(part.IndexCount, part.IndexStart, 0); + } + } + + ID3D11ShaderResourceView* nullSRVs[32] = { nullptr }; + context->PSSetShaderResources(0, ArraySize_(nullSRVs), nullSRVs); +} + +// Renders all meshes using depth-only rendering +void MeshRenderer::RenderDepth(ID3D11DeviceContext* context, const Camera& camera, bool noZClip, bool flippedZRange) +{ + PIXEvent event(L"Mesh Depth Rendering"); + + // Set states + float blendFactor[4] = {1, 1, 1, 1}; + context->OMSetBlendState(blendStates.ColorWriteDisabled(), blendFactor, 0xFFFFFFFF); + context->OMSetDepthStencilState(flippedZRange ? depthStencilStates.ReverseDepthWriteEnabled() + : depthStencilStates.DepthWriteEnabled(), 0); + + if(noZClip) + context->RSSetState(noZClipRSState); + else + context->RSSetState(rasterizerStates.NoCull()); + + // Set constant buffers + meshVSConstants.Data.World = Float4x4(); + meshVSConstants.Data.View = Float4x4::Transpose(camera.ViewMatrix()); + meshVSConstants.Data.WorldViewProjection = Float4x4::Transpose(camera.ViewProjectionMatrix()); + meshVSConstants.ApplyChanges(context); + meshVSConstants.SetVS(context, 0); + + // Set shaders + context->VSSetShader(meshDepthVS , nullptr, 0); + context->PSSetShader(nullptr, nullptr, 0); + context->GSSetShader(nullptr, nullptr, 0); + context->DSSetShader(nullptr, nullptr, 0); + context->HSSetShader(nullptr, nullptr, 0); + + for(uint32 meshIdx = 0; meshIdx < sceneModel->Meshes().size(); ++meshIdx) + { + const Mesh& mesh = sceneModel->Meshes()[meshIdx]; + + // Set the vertices and indices + ID3D11Buffer* vertexBuffers[1] = { mesh.VertexBuffer() }; + UINT vertexStrides[1] = { mesh.VertexStride() }; + UINT offsets[1] = { 0 }; + context->IASetVertexBuffers(0, 1, vertexBuffers, vertexStrides, offsets); + context->IASetIndexBuffer(mesh.IndexBuffer(), mesh.IndexBufferFormat(), 0); + context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + // Set the input layout + context->IASetInputLayout(meshDepthInputLayouts[meshIdx]); + + // Draw all parts + for(uint64 partIdx = 0; partIdx < mesh.MeshParts().size(); ++partIdx) + { + const MeshPart& part = mesh.MeshParts()[partIdx]; + context->DrawIndexed(part.IndexCount, part.IndexStart, 0); + } + } +} + +// Renders meshes using cascaded shadow mapping +void MeshRenderer::RenderSunShadowMap(ID3D11DeviceContext* context, const Camera& camera, bool useReductionDepth) +{ + PIXEvent event(L"Sun Shadow Map Rendering"); + + const float MinDistance = useReductionDepth ? reductionDepth.x : 0.0f; + const float MaxDistance = useReductionDepth ? reductionDepth.y : 1.0f; + + // Compute the split distances based on the partitioning mode + float CascadeSplits[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + + if(camera.IsOrthographic()) + { + for(uint32 i = 0; i < NumCascades; ++i) + CascadeSplits[i] = Lerp(MinDistance, MaxDistance, (i + 1.0f) / NumCascades); + } + else + { + float lambda = 1.0f; + + float nearClip = camera.NearClip(); + float farClip = camera.FarClip(); + float clipRange = farClip - nearClip; + + float minZ = nearClip + MinDistance * clipRange; + float maxZ = nearClip + MaxDistance * clipRange; + + float range = maxZ - minZ; + float ratio = maxZ / minZ; + + for(uint32 i = 0; i < NumCascades; ++i) + { + float p = (i + 1) / static_cast(NumCascades); + float log = minZ * std::pow(ratio, p); + float uniform = minZ + range * p; + float d = lambda * (log - uniform) + uniform; + CascadeSplits[i] = (d - nearClip) / clipRange; + } + } + + Float3 c0Extents; + Float4x4 c0Matrix; + + const Float3 lightDir = AppSettings::SunDirection; + + // Render the meshes to each cascade + for(uint32 cascadeIdx = 0; cascadeIdx < NumCascades; ++cascadeIdx) + { + PIXEvent cascadeEvent((L"Rendering Shadow Map Cascade " + ToString(cascadeIdx)).c_str()); + + // Set the viewport + SetViewport(context, ShadowMapSize, ShadowMapSize); + + // Set the shadow map as the depth target + ID3D11DepthStencilView* dsv = sunShadowDepthMap.DSView; + ID3D11RenderTargetView* nullRenderTargets[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = { nullptr }; + context->OMSetRenderTargets(D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT, nullRenderTargets, dsv); + context->ClearDepthStencilView(dsv, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 1.0f, 0); + + // Get the 8 points of the view frustum in world space + XMVECTOR frustumCornersWS[8] = + { + XMVectorSet(-1.0f, 1.0f, 0.0f, 1.0f), + XMVectorSet( 1.0f, 1.0f, 0.0f, 1.0f), + XMVectorSet( 1.0f, -1.0f, 0.0f, 1.0f), + XMVectorSet(-1.0f, -1.0f, 0.0f, 1.0f), + XMVectorSet(-1.0f, 1.0f, 1.0f, 1.0f), + XMVectorSet( 1.0f, 1.0f, 1.0f, 1.0f), + XMVectorSet( 1.0f, -1.0f, 1.0f, 1.0f), + XMVectorSet(-1.0f, -1.0f, 1.0f, 1.0f), + }; + + float prevSplitDist = cascadeIdx == 0 ? MinDistance : CascadeSplits[cascadeIdx - 1]; + float splitDist = CascadeSplits[cascadeIdx]; + + XMVECTOR det; + XMMATRIX invViewProj = XMMatrixInverse(&det, camera.ViewProjectionMatrix().ToSIMD()); + for(uint32 i = 0; i < 8; ++i) + frustumCornersWS[i] = XMVector3TransformCoord(frustumCornersWS[i], invViewProj); + + // Get the corners of the current cascade slice of the view frustum + for(uint32 i = 0; i < 4; ++i) + { + XMVECTOR cornerRay = XMVectorSubtract(frustumCornersWS[i + 4], frustumCornersWS[i]); + XMVECTOR nearCornerRay = XMVectorScale(cornerRay, prevSplitDist); + XMVECTOR farCornerRay = XMVectorScale(cornerRay, splitDist); + frustumCornersWS[i + 4] = XMVectorAdd(frustumCornersWS[i], farCornerRay); + frustumCornersWS[i] = XMVectorAdd(frustumCornersWS[i], nearCornerRay); + } + + // Calculate the centroid of the view frustum slice + XMVECTOR frustumCenterVec = XMVectorZero(); + for(uint32 i = 0; i < 8; ++i) + frustumCenterVec = XMVectorAdd(frustumCenterVec, frustumCornersWS[i]); + frustumCenterVec = XMVectorScale(frustumCenterVec, 1.0f / 8.0f); + Float3 frustumCenter = frustumCenterVec; + + // Pick the up vector to use for the light camera + Float3 upDir = camera.Right(); + + Float3 minExtents; + Float3 maxExtents; + + { + // Create a temporary view matrix for the light + Float3 lightCameraPos = frustumCenter; + Float3 lookAt = frustumCenter - lightDir; + XMMATRIX lightView = XMMatrixLookAtLH(lightCameraPos.ToSIMD(), lookAt.ToSIMD(), upDir.ToSIMD()); + + // Calculate an AABB around the frustum corners + XMVECTOR mins = XMVectorSet(REAL_MAX, REAL_MAX, REAL_MAX, REAL_MAX); + XMVECTOR maxes = XMVectorSet(-REAL_MAX, -REAL_MAX, -REAL_MAX, -REAL_MAX); + for(uint32 i = 0; i < 8; ++i) + { + XMVECTOR corner = XMVector3TransformCoord(frustumCornersWS[i], lightView); + mins = XMVectorMin(mins, corner); + maxes = XMVectorMax(maxes, corner); + } + + minExtents = mins; + maxExtents = maxes; + } + + // Adjust the min/max to accommodate the filtering size + float scale = (ShadowMapSize + FilterSize) / static_cast(ShadowMapSize); + minExtents.x *= scale; + minExtents.y *= scale; + maxExtents.x *= scale; + maxExtents.y *= scale; + + Float3 cascadeExtents = maxExtents - minExtents; + + // Get position of the shadow camera + Float3 shadowCameraPos = frustumCenter + lightDir * -minExtents.z; + + // Come up with a new orthographic camera for the shadow caster + OrthographicCamera shadowCamera(minExtents.x, minExtents.y, maxExtents.x, + maxExtents.y, 0.0f, cascadeExtents.z); + shadowCamera.SetLookAt(shadowCameraPos, frustumCenter, upDir); + + // Draw the mesh with depth only, using the new shadow camera + RenderDepth(context, shadowCamera, true, false); + + // Apply the scale/offset matrix, which transforms from [-1,1] + // post-projection space to [0,1] UV space + XMMATRIX texScaleBias; + texScaleBias.r[0] = XMVectorSet(0.5f, 0.0f, 0.0f, 0.0f); + texScaleBias.r[1] = XMVectorSet(0.0f, -0.5f, 0.0f, 0.0f); + texScaleBias.r[2] = XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f); + texScaleBias.r[3] = XMVectorSet(0.5f, 0.5f, 0.0f, 1.0f); + XMMATRIX shadowMatrix = shadowCamera.ViewProjectionMatrix().ToSIMD(); + shadowMatrix = XMMatrixMultiply(shadowMatrix, texScaleBias); + + // Store the split distance in terms of view space depth + const float clipDist = camera.FarClip() - camera.NearClip(); + meshPSConstants.Data.CascadeSplits[cascadeIdx] = camera.NearClip() + splitDist * clipDist; + + if(cascadeIdx == 0) + { + c0Extents = cascadeExtents; + c0Matrix = shadowMatrix; + meshPSConstants.Data.ShadowMatrix = XMMatrixTranspose(shadowMatrix); + meshPSConstants.Data.CascadeOffsets[0] = Float4(0.0f, 0.0f, 0.0f, 0.0f); + meshPSConstants.Data.CascadeScales[0] = Float4(1.0f, 1.0f, 1.0f, 1.0f); + } + else + { + // Calculate the position of the lower corner of the cascade partition, in the UV space + // of the first cascade partition + Float4x4 invCascadeMat = Float4x4::Invert(shadowMatrix); + Float3 cascadeCorner = Float3::Transform(Float3(0.0f, 0.0f, 0.0f), invCascadeMat); + cascadeCorner = Float3::Transform(cascadeCorner, c0Matrix); + + // Do the same for the upper corner + Float3 otherCorner = Float3::Transform(Float3(1.0f, 1.0f, 1.0f), invCascadeMat); + otherCorner = Float3::Transform(otherCorner, c0Matrix); + + // Calculate the scale and offset + Float3 cascadeScale = Float3(1.0f, 1.0f, 1.f) / (otherCorner - cascadeCorner); + meshPSConstants.Data.CascadeOffsets[cascadeIdx] = Float4(-cascadeCorner, 0.0f); + meshPSConstants.Data.CascadeScales[cascadeIdx] = Float4(cascadeScale, 1.0f); + } + + ConvertToEVSM(context, cascadeIdx, meshPSConstants.Data.CascadeScales[cascadeIdx].To3D()); + } +} + +// Renders an omni-directional shadow map for the spherical area light +void MeshRenderer::RenderAreaLightShadowMap(ID3D11DeviceContext* context, const Camera& camera) +{ + PIXEvent event(L"Area Light Shadow Map Rendering"); + + const uint32 sMapSize = areaLightShadowMap.Width; + const Float3 areaLightPos = Float3(AppSettings::AreaLightX, AppSettings::AreaLightY, AppSettings::AreaLightZ); + const float nearClip = AppSettings::AreaLightSize; + + for(uint64 face = 0; face < 6; ++face) + { + PIXEvent faceEvent(L"Area Light Shadow Map Face " + ToString(face)); + + // Set the viewport + SetViewport(context, sMapSize, sMapSize); + + // Set the shadow map as the depth target + ID3D11DepthStencilView* dsv = areaLightShadowMap.ArraySlices[face]; + ID3D11RenderTargetView* nullRenderTargets[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = { nullptr }; + context->OMSetRenderTargets(D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT, nullRenderTargets, dsv); + context->ClearDepthStencilView(dsv, D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL, 0.0f, 0); + + PerspectiveCamera shadowCamera(1.0f, Pi_2, nearClip, nearClip + 1.0f); + + // Set up a infinite reverse projection + Float4x4 projection; + projection._33 = 0.0f; + projection._43 = nearClip; + projection._34 = 1.0f; + projection._44 = 0.0f; + shadowCamera.SetProjection(projection); + + static const Float3 LookAtDirs[6] = + { + Float3(1.0f, 0.0f, 0.0f), Float3(-1.0f, 0.0f, 0.0f), + Float3(0.0f, 1.0f, 0.0f), Float3(0.0f, -1.0f, 0.0f), + Float3(0.0f, 0.0f, 1.0f), Float3(0.0f, 0.0f, -1.0f) + }; + + static const Float3 UpDirs[6] = { + Float3(0.0f, 1.0f, 0.0f), Float3(0.0f, 1.0f, 0.0f), + Float3(0.0f, 0.0f, -1.0f), Float3(0.0f, 0.0f, 1.0f), + Float3(0.0f, 1.0f, 0.0f), Float3(0.0f, 1.0f, 0.0f), + }; + + shadowCamera.SetLookAt(areaLightPos, areaLightPos + LookAtDirs[face], UpDirs[face]); + + RenderDepth(context, shadowCamera, false, true); + } +} + +// Renders the area light +void MeshRenderer::RenderAreaLight(ID3D11DeviceContext* context, const Camera& camera) +{ + PIXEvent event(L"Area Light Rendering"); + + // Set states + float blendFactor[4] = {1, 1, 1, 1}; + context->OMSetBlendState(blendStates.BlendDisabled(), blendFactor, 0xFFFFFFFF); + context->OMSetDepthStencilState(depthStencilStates.DepthWriteEnabled(), 0); + context->RSSetState(rasterizerStates.NoCull()); + + // Set constant buffers + areaLightConstants.Data.ViewProjection = Float4x4::Transpose(camera.ViewProjectionMatrix()); + areaLightConstants.Data.PrevViewProjection = Float4x4::Transpose(prevVP); + areaLightConstants.ApplyChanges(context); + areaLightConstants.SetVS(context, 0); + areaLightConstants.SetPS(context, 0); + + // Set shaders + context->DSSetShader(nullptr, nullptr, 0); + context->HSSetShader(nullptr, nullptr, 0); + context->GSSetShader(nullptr, nullptr, 0); + context->VSSetShader(areaLightVS , nullptr, 0); + context->PSSetShader(areaLightPS, nullptr, 0); + + // Draw the visualizer sphere + ID3D11Buffer* vertexBuffers[1] = { sphereVB }; + uint32 vertexStrides[1] = { sizeof(Float3) }; + uint32 offsets[1] = { 0 }; + context->IASetVertexBuffers(0, 1, vertexBuffers, vertexStrides, offsets); + context->IASetIndexBuffer(sphereIB, DXGI_FORMAT_R32_UINT, 0); + context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + context->IASetInputLayout(areaLightInputLayout); + context->DrawIndexedInstanced(uint32(numSphereIndices), 1, 0, 0, 0); +} + +// Renders the bake data visualizer +void MeshRenderer::RenderBakeDataVisualizer(ID3D11DeviceContext* context, const Camera& camera, const MeshBakerStatus& status) +{ + PIXEvent event(L"Bake Data Visualizer"); + + // Set states + float blendFactor[4] = {1, 1, 1, 1}; + context->OMSetBlendState(blendStates.BlendDisabled(), blendFactor, 0xFFFFFFFF); + context->OMSetDepthStencilState(depthStencilStates.DepthWriteEnabled(), 0); + context->RSSetState(rasterizerStates.NoCull()); + + // Set constant buffers + visualizerConstants.Data.ViewProjection = Float4x4::Transpose(camera.ViewProjectionMatrix()); + for(uint64 i = 0; i < ArraySize_(status.SGDirections); ++i) + visualizerConstants.Data.SGDirections[i] = Float4(status.SGDirections[i], 0.0f); + visualizerConstants.Data.SGSharpness = status.SGSharpness; + visualizerConstants.Data.SceneMinBounds = status.SceneMinBounds; + visualizerConstants.Data.SceneMaxBounds = status.SceneMaxBounds; + visualizerConstants.ApplyChanges(context); + visualizerConstants.SetVS(context, 0); + visualizerConstants.SetPS(context, 0); + + // Set shaders + context->DSSetShader(nullptr, nullptr, 0); + context->HSSetShader(nullptr, nullptr, 0); + context->GSSetShader(nullptr, nullptr, 0); + context->VSSetShader(visualizerVS , nullptr, 0); + context->PSSetShader(visualizerPS, nullptr, 0); + + ID3D11ShaderResourceView* vsSrvs[] = { status.BakePoints }; + context->VSSetShaderResources(0, ArraySize_(vsSrvs), vsSrvs); + + ID3D11ShaderResourceView* psSrvs[] = { status.LightMap }; + context->PSSetShaderResources(0, ArraySize_(psSrvs), psSrvs); + + ID3D11SamplerState* psSamplers[] = { samplerStates.LinearClamp() }; + context->PSSetSamplers(0, ArraySize_(psSamplers), psSamplers); + + // Draw the visualizer hemispheres for all sample points + ID3D11Buffer* vertexBuffers[1] = { hemisphereVB }; + uint32 vertexStrides[1] = { sizeof(Float3) }; + uint32 offsets[1] = { 0 }; + context->IASetVertexBuffers(0, 1, vertexBuffers, vertexStrides, offsets); + context->IASetIndexBuffer(hemisphereIB, DXGI_FORMAT_R32_UINT, 0); + context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + context->IASetInputLayout(visualizerInputLayout); + + // Draw + context->DrawIndexedInstanced(uint32(numHemisphereIndices), uint32(status.NumBakePoints), 0, 0, 0); + + ID3D11ShaderResourceView* nullSRVs[] = { nullptr }; + context->VSSetShaderResources(0, 1, nullSRVs); + context->PSSetShaderResources(0, 1, nullSRVs); +} + +// Renders the probe visualizer +void MeshRenderer::RenderProbeVisualizer(ID3D11DeviceContext* context, const Camera& camera, const MeshBakerStatus& status) +{ + PIXEvent event(L"Probe Visualizer"); + + // Set states + float blendFactor[4] = {1, 1, 1, 1}; + context->OMSetBlendState(blendStates.BlendDisabled(), blendFactor, 0xFFFFFFFF); + context->OMSetDepthStencilState(depthStencilStates.DepthWriteEnabled(), 0); + context->RSSetState(rasterizerStates.NoCull()); + + // Set constant buffers + visualizerConstants.Data.ViewProjection = Float4x4::Transpose(camera.ViewProjectionMatrix()); + for(uint64 i = 0; i < ArraySize_(status.SGDirections); ++i) + visualizerConstants.Data.SGDirections[i] = Float4(status.SGDirections[i], 0.0f); + visualizerConstants.Data.SGSharpness = status.SGSharpness; + visualizerConstants.Data.SceneMinBounds = status.SceneMinBounds; + visualizerConstants.Data.SceneMaxBounds = status.SceneMaxBounds; + visualizerConstants.ApplyChanges(context); + visualizerConstants.SetVS(context, 0); + visualizerConstants.SetPS(context, 0); + + // Set shaders + context->DSSetShader(nullptr, nullptr, 0); + context->HSSetShader(nullptr, nullptr, 0); + context->GSSetShader(nullptr, nullptr, 0); + context->VSSetShader(probeVisualizerVS , nullptr, 0); + context->PSSetShader(probeVisualizerPS, nullptr, 0); + + ID3D11ShaderResourceView* psSrvs[] = { status.ProbeIrradianceCubeMap, status.ProbeDistanceCubeMap }; + context->PSSetShaderResources(0, ArraySize_(psSrvs), psSrvs); + + uint32 offset = ArraySize_(psSrvs); + context->PSSetShaderResources(offset, ArraySize_(status.ProbeVolumeMaps), status.ProbeVolumeMaps); + + offset += ArraySize_(status.ProbeVolumeMaps); + context->PSSetShaderResources(offset, ArraySize_(status.ProbeDistanceVolumeMaps), status.ProbeDistanceVolumeMaps); + + ID3D11SamplerState* psSamplers[] = { samplerStates.LinearClamp() }; + context->PSSetSamplers(0, ArraySize_(psSamplers), psSamplers); + + // Draw the visualizer hemispheres for all sample points + ID3D11Buffer* vertexBuffers[1] = { sphereVB }; + uint32 vertexStrides[1] = { sizeof(Float3) }; + uint32 offsets[1] = { 0 }; + context->IASetVertexBuffers(0, 1, vertexBuffers, vertexStrides, offsets); + context->IASetIndexBuffer(sphereIB, DXGI_FORMAT_R32_UINT, 0); + context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + context->IASetInputLayout(probeVisualizerInputLayout); + + // Draw + context->DrawIndexedInstanced(uint32(numSphereIndices), uint32(AppSettings::NumProbes()), 0, 0, 0); + + ID3D11ShaderResourceView* nullSRVs[2] = { }; + context->PSSetShaderResources(0, ArraySize_(nullSRVs), nullSRVs); +} + +void MeshRenderer::RenderVoxelVisualizer(ID3D11DeviceContext* context, const Camera& camera, const MeshBakerStatus& status) +{ + PIXEvent event(L"Voxel Visualizer"); + + // Set constant buffers + voxelVisualizerConstants.Data.ViewProjection = Float4x4::Transpose(camera.ViewProjectionMatrix()); + voxelVisualizerConstants.Data.SceneMinBounds = status.SceneMinBounds; + voxelVisualizerConstants.Data.SceneMaxBounds = status.SceneMaxBounds; + voxelVisualizerConstants.Data.CameraPos = camera.Position(); + + uint32 mipVoxelRes = AppSettings::VoxelResolution; + for(int32 i = 0; i < AppSettings::VoxelVisualizerMipLevel; ++i) + mipVoxelRes = Max(mipVoxelRes / 2, 1u); + voxelVisualizerConstants.Data.MipVoxelRes = float(mipVoxelRes); + + voxelVisualizerConstants.ApplyChanges(context); + voxelVisualizerConstants.SetVS(context, 0); + voxelVisualizerConstants.SetPS(context, 0); + + // Set shaders + context->DSSetShader(nullptr, nullptr, 0); + context->HSSetShader(nullptr, nullptr, 0); + context->GSSetShader(nullptr, nullptr, 0); + + ID3D11ShaderResourceView* srvs[7] = { status.VoxelRadiance }; + for(uint64 i = 0; i < 6; ++i) + srvs[i + 1] = status.VoxelRadianceMips[i]; + + context->VSSetShaderResources(0, ArraySize_(srvs), srvs); + context->PSSetShaderResources(0, ArraySize_(srvs), srvs); + + ID3D11SamplerState* samplers[] = { samplerStates.Point() }; + context->PSSetSamplers(0, ArraySize_(samplers), samplers); + + // Draw a box for each voxel + ID3D11Buffer* vertexBuffers[1] = { voxelVisualizerVB }; + uint32 vertexStrides[1] = { sizeof(Float3) }; + uint32 offsets[1] = { 0 }; + context->IASetVertexBuffers(0, 1, vertexBuffers, vertexStrides, offsets); + context->IASetIndexBuffer(voxelVisualizerIB, DXGI_FORMAT_R16_UINT, 0); + context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + if(AppSettings::VoxelVisualizerMode == VoxelVisualizerModes::Geometry) + { + // Set states + float blendFactor[4] = {1, 1, 1, 1}; + context->OMSetBlendState(blendStates.BlendDisabled(), blendFactor, 0xFFFFFFFF); + context->OMSetDepthStencilState(depthStencilStates.DepthWriteEnabled(), 0); + context->RSSetState(rasterizerStates.BackFaceCull()); + + context->IASetInputLayout(voxelGeoIL); + + context->VSSetShader(voxelGeoVS , nullptr, 0); + context->PSSetShader(voxelGeoPS, nullptr, 0); + + const uint32 numVoxels = AppSettings::VoxelResolution * AppSettings::VoxelResolution * AppSettings::VoxelResolution; + context->DrawIndexedInstanced(NumBoxIndices, numVoxels, 0, 0, 0); + } + else if(AppSettings::VoxelVisualizerMode == VoxelVisualizerModes::RayMarch) + { + // Set states + float blendFactor[4] = {1, 1, 1, 1}; + context->OMSetBlendState(blendStates.AlphaBlend(), blendFactor, 0xFFFFFFFF); + context->OMSetDepthStencilState(depthStencilStates.DepthDisabled(), 0); + context->RSSetState(rasterizerStates.FrontFaceCull()); + + context->IASetInputLayout(voxelRayMarchIL); + + context->VSSetShader(voxelRayMarchVS , nullptr, 0); + context->PSSetShader(AppSettings::VoxelVisualizerMipLevel == 0 ? voxelRayMarchFirstMipPS : voxelRayMarchPS, nullptr, 0); + + context->DrawIndexedInstanced(NumBoxIndices, 1, 0, 0, 0); + } + + for(uint64 i = 0; i < ArraySize_(srvs); ++i) + srvs[i] = nullptr; + context->VSSetShaderResources(0, ArraySize_(srvs), srvs); + context->PSSetShaderResources(0, ArraySize_(srvs), srvs); } \ No newline at end of file diff --git a/BakingLab/MeshRenderer.h b/BakingLab/MeshRenderer.h index f3295d6..4a01f25 100644 --- a/BakingLab/MeshRenderer.h +++ b/BakingLab/MeshRenderer.h @@ -1,201 +1,241 @@ -//================================================================================================= -// -// Baking Lab -// by MJP and David Neubelt -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -#pragma once - -#include - -#include -#include -#include -#include -#include -#include - -#include "AppSettings.h" - -using namespace SampleFramework11; - -struct MeshBakerStatus; - -class MeshRenderer -{ - -protected: - - // Constants - static const uint32 NumCascades = 4; - static const uint32 ReadbackLatency = 1; - -public: -MeshRenderer(); - - void Initialize(ID3D11Device* device, ID3D11DeviceContext* context, const Model* sceneModel); - void SetModel(const Model* model); - - void RenderDepth(ID3D11DeviceContext* context, const Camera& camera, bool noZClip, bool flippedZRange); - void RenderMainPass(ID3D11DeviceContext* context, const Camera& camera, const MeshBakerStatus& status); - - void Update(const Camera& camera, Float2 jitterOffset); - - void OnResize(uint32 width, uint32 height); - - void ReduceDepth(ID3D11DeviceContext* context, DepthStencilBuffer& depthTarget, - const Camera& camera); - - void RenderSunShadowMap(ID3D11DeviceContext* context, const Camera& camera); - void RenderAreaLightShadowMap(ID3D11DeviceContext* context, const Camera& camera); - - void RenderAreaLight(ID3D11DeviceContext* context, const Camera& camera); - void RenderBakeDataVisualizer(ID3D11DeviceContext* context, const Camera& camera, - const MeshBakerStatus& status); - -protected: - - void LoadShaders(); - void CreateShadowMaps(); - void ConvertToEVSM(ID3D11DeviceContext* context, uint32 cascadeIdx, Float3 cascadeScale); - - ID3D11DevicePtr device; - - BlendStates blendStates; - RasterizerStates rasterizerStates; - DepthStencilStates depthStencilStates; - SamplerStates samplerStates; - - const Model* sceneModel; - - DepthStencilBuffer sunShadowDepthMap; - RenderTarget2D sunVSM; - RenderTarget2D tempVSM; - - DepthStencilBuffer areaLightShadowMap; - - ID3D11RasterizerStatePtr noZClipRSState; - ID3D11SamplerStatePtr evsmSampler; - - std::vector meshInputLayouts; - VertexShaderPtr meshVS; - PixelShaderPtr meshPS; - - std::vector meshDepthInputLayouts; - VertexShaderPtr meshDepthVS; - - ID3D11BufferPtr hemisphereVB; - ID3D11BufferPtr hemisphereIB; - uint64 numHemisphereIndices; - - ID3D11InputLayoutPtr visualizerInputLayout; - VertexShaderPtr visualizerVS; - PixelShaderPtr visualizerPS; - - ID3D11BufferPtr areaLightVB; - ID3D11BufferPtr areaLightIB; - uint64 numAreaLightIndices; - - VertexShaderPtr areaLightVS; - PixelShaderPtr areaLightPS; - ID3D11InputLayoutPtr areaLightInputLayout; - - VertexShaderPtr fullScreenVS; - PixelShaderPtr evsmConvertPS; - PixelShaderPtr evsmBlurH; - PixelShaderPtr evsmBlurV; - - ComputeShaderPtr depthReductionInitialCS[2]; - ComputeShaderPtr depthReductionCS; - std::vector depthReductionTargets; - StagingTexture2D reductionStagingTextures[ReadbackLatency]; - uint32 currFrame; - - Float2 reductionDepth; - - Float4x4 prevVP; - Float4x4 currVP; - bool firstFrame = true; - - ID3D11ShaderResourceViewPtr shSpecularLookupA; - ID3D11ShaderResourceViewPtr shSpecularLookupB; - - // Constant buffers - struct MeshVSConstants - { - Float4Align Float4x4 World; - Float4Align Float4x4 View; - Float4Align Float4x4 WorldViewProjection; - Float4Align Float4x4 PrevWorldViewProjection; - }; - - struct MeshPSConstants - { - Float4Align Float3 SunDirectionWS; - float CosSunAngularRadius; - Float4Align Float3 SunIlluminance; - float SinSunAngularRadius; - Float4Align Float3 CameraPosWS; - - Float4Align Float4x4 ShadowMatrix; - Float4Align float CascadeSplits[NumCascades]; - - Float4Align Float4 CascadeOffsets[NumCascades]; - Float4Align Float4 CascadeScales[NumCascades]; - - float OffsetScale; - float PositiveExponent; - float NegativeExponent; - float LightBleedingReduction; - - Float2 RTSize; - Float2 JitterOffset; - - Float4Align Float4 SGDirections[AppSettings::MaxSGCount]; - float SGSharpness; - }; - - struct AreaLightConstants - { - Float4x4 ViewProjection; - Float4x4 PrevViewProjection; - Float2 RTSize; - Float2 JitterOffset; - }; - - struct EVSMConstants - { - Float3 CascadeScale; - float PositiveExponent; - float NegativeExponent; - float FilterSize; - Float2 ShadowMapSize; - }; - - struct ReductionConstants - { - Float4x4 Projection; - float NearClip; - float FarClip; - Uint2 TextureSize; - uint32 NumSamples; - }; - - struct VisualizerConstants - { - Float4x4 ViewProjection; - Float4Align Float4 SGDirections[AppSettings::MaxSGCount]; - float SGSharpness; - }; - - ConstantBuffer meshVSConstants; - ConstantBuffer meshPSConstants; - ConstantBuffer areaLightConstants; - ConstantBuffer visualizerConstants; - ConstantBuffer evsmConstants; - ConstantBuffer reductionConstants; +//================================================================================================= +// +// Baking Lab +// by MJP and David Neubelt +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +#pragma once + +#include + +#include +#include +#include +#include +#include +#include + +#include "AppSettings.h" + +using namespace SampleFramework11; + +struct MeshBakerStatus; + +class MeshRenderer +{ + +protected: + + // Constants + static const uint32 NumCascades = 4; + static const uint32 ReadbackLatency = 1; + +public: + + void Initialize(ID3D11Device* device, ID3D11DeviceContext* context, const Model* sceneModel); + void SetModel(const Model* model); + + void RenderDepth(ID3D11DeviceContext* context, const Camera& camera, bool noZClip, bool flippedZRange); + void RenderMainPass(ID3D11DeviceContext* context, const Camera& camera, const MeshBakerStatus& status, + bool32 probeRendering, bool voxelizing); + + void Update(const Camera& camera, Float2 jitterOffset); + + void OnResize(uint32 width, uint32 height); + + void ReduceDepth(ID3D11DeviceContext* context, const DepthStencilBuffer& depthTarget, + const Camera& camera); + + void RenderSunShadowMap(ID3D11DeviceContext* context, const Camera& camera, bool useReductionDepth); + void RenderAreaLightShadowMap(ID3D11DeviceContext* context, const Camera& camera); + + void RenderAreaLight(ID3D11DeviceContext* context, const Camera& camera); + void RenderBakeDataVisualizer(ID3D11DeviceContext* context, const Camera& camera, + const MeshBakerStatus& status); + void RenderProbeVisualizer(ID3D11DeviceContext* context, const Camera& camera, + const MeshBakerStatus& status); + void MeshRenderer::RenderVoxelVisualizer(ID3D11DeviceContext* context, const Camera& camera, + const MeshBakerStatus& status); + +protected: + + void LoadShaders(); + void CreateShadowMaps(); + void ConvertToEVSM(ID3D11DeviceContext* context, uint32 cascadeIdx, Float3 cascadeScale); + + ID3D11DevicePtr device; + + BlendStates blendStates; + RasterizerStates rasterizerStates; + DepthStencilStates depthStencilStates; + SamplerStates samplerStates; + + const Model* sceneModel = nullptr; + + DepthStencilBuffer sunShadowDepthMap; + RenderTarget2D sunVSM; + RenderTarget2D tempVSM; + + DepthStencilBuffer areaLightShadowMap; + + ID3D11RasterizerStatePtr noZClipRSState; + ID3D11SamplerStatePtr evsmSampler; + + std::vector meshInputLayouts; + VertexShaderPtr meshVS; + VertexShaderPtr meshVSVoxelize; + PixelShaderPtr meshPS; + PixelShaderPtr meshPSProbes; + PixelShaderPtr meshPSVoxelize; + + std::vector meshDepthInputLayouts; + VertexShaderPtr meshDepthVS; + + ID3D11BufferPtr hemisphereVB; + ID3D11BufferPtr hemisphereIB; + uint64 numHemisphereIndices = 0; + + ID3D11InputLayoutPtr visualizerInputLayout; + VertexShaderPtr visualizerVS; + PixelShaderPtr visualizerPS; + + ID3D11InputLayoutPtr probeVisualizerInputLayout; + VertexShaderPtr probeVisualizerVS; + PixelShaderPtr probeVisualizerPS; + + ID3D11BufferPtr sphereVB; + ID3D11BufferPtr sphereIB; + uint64 numSphereIndices = 0; + + VertexShaderPtr areaLightVS; + PixelShaderPtr areaLightPS; + ID3D11InputLayoutPtr areaLightInputLayout; + + VertexShaderPtr fullScreenVS; + PixelShaderPtr evsmConvertPS; + PixelShaderPtr evsmBlurH; + PixelShaderPtr evsmBlurV; + + ComputeShaderPtr depthReductionInitialCS[2]; + ComputeShaderPtr depthReductionCS; + std::vector depthReductionTargets; + StagingTexture2D reductionStagingTextures[ReadbackLatency]; + uint32 currFrame = 0; + + Float2 reductionDepth; + + Float4x4 prevVP; + Float4x4 currVP; + bool firstFrame = true; + + ID3D11ShaderResourceViewPtr shSpecularLookupA; + ID3D11ShaderResourceViewPtr shSpecularLookupB; + + VertexShaderPtr voxelGeoVS; + PixelShaderPtr voxelGeoPS; + ID3D11InputLayoutPtr voxelGeoIL; + + VertexShaderPtr voxelRayMarchVS; + PixelShaderPtr voxelRayMarchFirstMipPS; + PixelShaderPtr voxelRayMarchPS; + ID3D11InputLayoutPtr voxelRayMarchIL; + + ID3D11BufferPtr voxelVisualizerVB; + ID3D11BufferPtr voxelVisualizerIB; + + // Constant buffers + struct MeshVSConstants + { + Float4Align Float4x4 World; + Float4Align Float4x4 View; + Float4Align Float4x4 WorldViewProjection; + Float4Align Float4x4 PrevWorldViewProjection; + }; + + struct MeshPSConstants + { + Float4Align Float3 SunDirectionWS; + float CosSunAngularRadius; + Float4Align Float3 SunIlluminance; + float SinSunAngularRadius; + Float4Align Float3 CameraPosWS; + + Float4Align Float4x4 ShadowMatrix; + Float4Align float CascadeSplits[NumCascades]; + + Float4Align Float4 CascadeOffsets[NumCascades]; + Float4Align Float4 CascadeScales[NumCascades]; + + float OffsetScale; + float PositiveExponent; + float NegativeExponent; + float LightBleedingReduction; + + Float2 RTSize; + Float2 JitterOffset; + + Float4Align Float4 SGDirections[AppSettings::MaxSGCount]; + float SGSharpness; + + Float3 SceneMinBounds; + Float4Align Float3 SceneMaxBounds; + + Float4Align ShaderSH9Color SkySH; + }; + + struct AreaLightConstants + { + Float4x4 ViewProjection; + Float4x4 PrevViewProjection; + Float2 RTSize; + Float2 JitterOffset; + }; + + struct EVSMConstants + { + Float3 CascadeScale; + float PositiveExponent; + float NegativeExponent; + float FilterSize; + Float2 ShadowMapSize; + }; + + struct ReductionConstants + { + Float4x4 Projection; + float NearClip; + float FarClip; + Uint2 TextureSize; + uint32 NumSamples; + }; + + struct VisualizerConstants + { + Float4x4 ViewProjection; + Float4Align Float4 SGDirections[AppSettings::MaxSGCount]; + float SGSharpness; + Float3 SceneMinBounds; + Float4Align Float3 SceneMaxBounds; + }; + + struct VoxelVisualizerConstants + { + Float4x4 ViewProjection; + Float4Align Float3 SceneMinBounds; + Float4Align Float3 SceneMaxBounds; + Float4Align Float3 CameraPos; + float MipVoxelRes; + }; + + ConstantBuffer meshVSConstants; + ConstantBuffer meshPSConstants; + ConstantBuffer areaLightConstants; + ConstantBuffer visualizerConstants; + ConstantBuffer evsmConstants; + ConstantBuffer reductionConstants; + ConstantBuffer voxelVisualizerConstants; }; \ No newline at end of file diff --git a/BakingLab/ProbeIntegrate.hlsl b/BakingLab/ProbeIntegrate.hlsl new file mode 100644 index 0000000..1c3528c --- /dev/null +++ b/BakingLab/ProbeIntegrate.hlsl @@ -0,0 +1,282 @@ +//================================================================================================= +// +// Baking Lab +// by MJP and David Neubelt +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +#include +#include +#include +#include "AppSettings.hlsl" + +cbuffer IntegrateConstants : register(b0) +{ + float2 OutputTextureSize; + uint OutputProbeIdx; +} + +SamplerState LinearSampler : register(s0); + +float3 ComputeCubemapDirection(in uint2 pos, in uint face, in float2 textureSize) +{ + float u = ((pos.x + 0.5f) / textureSize.x) * 2.0f - 1.0f; + float v = ((pos.y + 0.5f) / textureSize.y) * 2.0f - 1.0f; + v *= -1.0f; + + float3 dir = 0.0f; + + // +x, -x, +y, -y, +z, -z + switch(face) + { + case 0: + dir = normalize(float3(1.0f, v, -u)); + break; + case 1: + dir = normalize(float3(-1.0f, v, u)); + break; + case 2: + dir = normalize(float3(u, 1.0f, -v)); + break; + case 3: + dir = normalize(float3(u, -1.0f, v)); + break; + case 4: + dir = normalize(float3(u, v, 1.0f)); + break; + case 5: + dir = normalize(float3(-u, v, -1.0f)); + break; + } + + return dir; +} + +// Computes a radical inverse with base 2 using crazy bit-twiddling from "Hacker's Delight" +float RadicalInverseBase2(in uint bits) +{ + bits = (bits << 16u) | (bits >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + return float(bits) * 2.3283064365386963e-10f; // / 0x100000000 +} + +// Returns a single 2D point in a Hammersley sequence of length "numSamples", using base 1 and base 2 +float2 Hammersley2D(in uint sampleIdx, in uint numSamples) +{ + return float2(float(sampleIdx) / float(numSamples), RadicalInverseBase2(sampleIdx)); +} + + +float3x3 MakeTangentFrame(in float3 normal, in uint faceIdx) +{ + float3 tangent = 0.0f; + if(faceIdx == 0) + tangent = float3(0.0f, 0.0f, -1.0f); + else if(faceIdx == 1) + tangent = float3(0.0f, 0.0f, 1.0f); + else if(faceIdx == 2) + tangent = float3(1.0f, 0.0f, 0.0f); + else if(faceIdx == 3) + tangent = float3(1.0f, 0.0f, 0.0f); + else if(faceIdx == 4) + tangent = float3(1.0f, 0.0f, 0.0f); + else if(faceIdx == 5) + tangent = float3(-1.0f, 0.0f, 0.0f); + + float3 bitangent = normalize(cross(normal, tangent)); + tangent = normalize(cross(bitangent, normal)); + + return float3x3(tangent, bitangent, normal); +} + +void IntegrateOntoBasis(in float3 dir, in float3 value, inout float3 output[MaxBasisCount]) +{ + if(ProbeMode == ProbeModes_AmbientCube) + { + output[0] += value * saturate(dir.x); + output[1] += value * saturate(dir.y); + output[2] += value * saturate(dir.z); + output[3] += value * saturate(-dir.x); + output[4] += value * saturate(-dir.y); + output[5] += value * saturate(-dir.z); + } + else if(ProbeMode == ProbeModes_L1_SH) + { + SH4Color sh = ProjectOntoSH4Color(dir, value); + + [unroll] + for(uint i = 0; i < 4; ++i) + output[i] += sh.c[i]; + } + else if(ProbeMode == ProbeModes_L2_SH) + { + SH9Color sh = ProjectOntoSH9Color(dir, value); + + [unroll] + for(uint i = 0; i < 9; ++i) + output[i] += sh.c[i]; + } +} + +// ================================================================================================ + +TextureCube RadianceCaptureMap : register(t0); +RWTexture2DArray IrradianceCubeMap : register(u0); + +[numthreads(8, 8, 1)] +void IntegrateIrradianceCubeMap(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : SV_GroupThreadID) +{ + uint2 outputPos = GroupID.xy * 8 + GroupThreadID.xy; + uint outputFaceIdx = GroupID.z; + uint outputSliceIdx = (OutputProbeIdx * 6) + outputFaceIdx; + + float3 normal = ComputeCubemapDirection(outputPos, outputFaceIdx, OutputTextureSize); + float3x3 tangentFrame = MakeTangentFrame(normal, outputFaceIdx); + + const uint numSamples = max(ProbeIntegrationSamples * ProbeIntegrationSamples, 1); + float3 irradiance = 0.0f; + for(uint i = 0; i < numSamples; ++i) + { + //float2 samplePos = Hammersley2D(i, numSamples); + uint pattern = (outputSliceIdx * ProbeIrradianceCubemapRes * ProbeIrradianceCubemapRes) + (outputPos.y * ProbeIrradianceCubemapRes) + outputPos.x; + float2 samplePos = SampleCMJ2D(i, ProbeIntegrationSamples, ProbeIntegrationSamples, pattern); + float3 sampleDir = SampleDirectionCosineHemisphere(samplePos.x, samplePos.y); + sampleDir = mul(sampleDir, tangentFrame); + float3 radiance = RadianceCaptureMap.SampleLevel(LinearSampler, sampleDir, 0.0f).xyz; + irradiance += radiance; + } + + irradiance *= (Pi / numSamples); + + // irradiance = 16.0f; + + IrradianceCubeMap[uint3(outputPos, outputSliceIdx)] = float4(irradiance, 0.0f); +} + +// ================================================================================================ + +RWTexture3D OutputVolumeMaps[MaxBasisCount] : register(u0); + +[numthreads(1, 1, 1)] +void IntegrateVolumeMap(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : SV_GroupThreadID) +{ + uint3 outputTexelIdx; + outputTexelIdx.x = OutputProbeIdx % ProbeResX; + outputTexelIdx.y = (OutputProbeIdx / ProbeResX) % ProbeResY; + outputTexelIdx.z = OutputProbeIdx / (ProbeResX * ProbeResY); + + float3 output[MaxBasisCount]; + for(int b = 0; b < MaxBasisCount; ++b) + output[b] = 0.0f; + + const uint numSamples = max(ProbeIntegrationSamples * ProbeIntegrationSamples, 1); + for(uint sampleIdx = 0; sampleIdx < numSamples; ++sampleIdx) + { + float2 samplePos = Hammersley2D(sampleIdx, numSamples); + float3 sampleDir = SampleDirectionSphere(samplePos.x, samplePos.y); + float3 radiance = RadianceCaptureMap.SampleLevel(LinearSampler, sampleDir, 0.0f).xyz; + + IntegrateOntoBasis(sampleDir, radiance, output); + } + + [unroll] + for(int i = 0; i < MaxBasisCount; ++i) + { + float3 outputValue = output[i] * (4 * Pi / numSamples); + OutputVolumeMaps[i][outputTexelIdx] = float4(clamp(outputValue, -FP16Max, FP16Max), 0.0f); + } +} + +// ================================================================================================ + +TextureCube DistanceCaptureMap : register(t0); +RWTexture2DArray DistanceOutputCubeMap : register(u0); + +float3 SampleCosinePower(in float2 xi, in float n) +{ + float phi = 2.0f * Pi * xi.x; + float theta = acos(pow(saturate(1.0f - xi.y), 1.0f /(n + 1.0f))); + + float3 dir; + dir.x = sin(theta) * cos(phi); + dir.y = sin(theta) * sin(phi); + dir.z = cos(theta); + + return dir; +} + +[numthreads(8, 8, 1)] +void IntegrateDistanceCubeMap(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : SV_GroupThreadID) +{ + uint2 outputPos = GroupID.xy * 8 + GroupThreadID.xy; + uint outputFaceIdx = GroupID.z; + uint outputSliceIdx = (OutputProbeIdx * 6) + outputFaceIdx; + + float3 normal = ComputeCubemapDirection(outputPos, outputFaceIdx, OutputTextureSize); + float3x3 tangentFrame = MakeTangentFrame(normal, outputFaceIdx); + + const uint numSamples = max(ProbeDistanceIntegrationSamples * ProbeDistanceIntegrationSamples, 1); + const float cosinePower = exp2(DistanceFilterSharpness); + + float2 outputDistance = 0.0f; + float weightSum = 0.0f; + for(uint i = 0; i < numSamples; ++i) + { + // float2 samplePos = Hammersley2D(i, numSamples); + uint pattern = (outputSliceIdx * ProbeDistanceCubemapRes * ProbeDistanceCubemapRes) + (outputPos.y * ProbeDistanceCubemapRes) + outputPos.x; + float2 samplePos = SampleCMJ2D(i, ProbeDistanceIntegrationSamples, ProbeDistanceIntegrationSamples, pattern); + float3 sampleDir = SampleCosinePower(samplePos, cosinePower); + sampleDir = mul(sampleDir, tangentFrame); + float2 sampleDistance = DistanceCaptureMap.SampleLevel(LinearSampler, sampleDir, 0.0f); + + float sampleWeight = ((cosinePower + 1.0f) / Pi2) * pow(saturate(dot(sampleDir, normal)), cosinePower); + outputDistance += sampleDistance * sampleWeight; + weightSum += sampleWeight; + } + + outputDistance *= (1.0f / weightSum); + + // outputDistance = DistanceCaptureMap.SampleLevel(LinearSampler, normal, 0.0f).xy; + + DistanceOutputCubeMap[uint3(outputPos, outputSliceIdx)] = outputDistance; +} + +// ================================================================================================ + +RWTexture3D OutputVolumeDistanceMaps[MaxBasisCount] : register(u0); + +[numthreads(1, 1, 1)] +void IntegrateDistanceVolumeMap(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : SV_GroupThreadID) +{ + uint3 outputTexelIdx; + outputTexelIdx.x = OutputProbeIdx % ProbeResX; + outputTexelIdx.y = (OutputProbeIdx / ProbeResX) % ProbeResY; + outputTexelIdx.z = OutputProbeIdx / (ProbeResX * ProbeResY); + + float3 output[MaxBasisCount]; + for(int b = 0; b < MaxBasisCount; ++b) + output[b] = 0.0f; + + const uint numSamples = max(ProbeIntegrationSamples * ProbeIntegrationSamples, 1); + for(uint sampleIdx = 0; sampleIdx < numSamples; ++sampleIdx) + { + float2 samplePos = Hammersley2D(sampleIdx, numSamples); + float3 sampleDir = SampleDirectionSphere(samplePos.x, samplePos.y); + float2 sampleDistance = DistanceCaptureMap.SampleLevel(LinearSampler, sampleDir, 0.0f); + + IntegrateOntoBasis(sampleDir, float3(sampleDistance, 0.0f), output); + } + + [unroll] + for(int i = 0; i < MaxBasisCount; ++i) + { + float2 outputValue = output[i].xy * (4 * Pi / numSamples); + OutputVolumeDistanceMaps[i][outputTexelIdx] = clamp(outputValue, -FP16Max, FP16Max); + } +} \ No newline at end of file diff --git a/BakingLab/ProbeVisualizer.hlsl b/BakingLab/ProbeVisualizer.hlsl new file mode 100644 index 0000000..a32424c --- /dev/null +++ b/BakingLab/ProbeVisualizer.hlsl @@ -0,0 +1,136 @@ +//================================================================================================= +// +// Baking Lab +// by MJP and David Neubelt +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +//================================================================================================= +// Includes +//================================================================================================= +#include "SharedConstants.h" +#include +#include "AppSettings.hlsl" +#include "SG.hlsl" + +//================================================================================================= +// Constant buffers +//================================================================================================= +cbuffer Constants : register(b0) +{ + float4x4 ViewProjection; + float4 SGDirections[MaxSGCount]; + float SGSharpness; + float3 SceneMinBounds; + float3 SceneMaxBounds; +} + +//================================================================================================= +// Resources +//================================================================================================= +TextureCubeArray ProbeIrradianceCubeMap : register(t0); +TextureCubeArray ProbeDistanceCubeMap : register(t1); +Texture3D ProbeVolumeMaps[MaxBasisCount]; +Texture3D ProbeDistanceVolumeMaps[MaxBasisCount]; +SamplerState LinearSampler : register(s0); + +//================================================================================================= +// Input/Output structs +//================================================================================================= +struct VSOutput +{ + float4 PositionCS : SV_Position; + float3 NormalWS : NORMALWS; + float3 ProbeUVW : PROBEUVW; + uint ProbeIdx : PROBEIDX; +}; + +struct PSInput +{ + float4 PositionSS : SV_Position; + float3 NormalWS : NORMALWS; + float3 ProbeUVW : PROBEUVW; + uint ProbeIdx : PROBEIDX; +}; + +//================================================================================================= +// Vertex shader +//================================================================================================= +VSOutput VS(in float3 SpherePosition : POSITION, in uint InstanceID : SV_InstanceID) +{ + VSOutput output; + + output.NormalWS = normalize(SpherePosition); + output.ProbeIdx = InstanceID; + + uint probeX = InstanceID % ProbeResX; + uint probeY = (InstanceID / ProbeResX) % ProbeResY; + uint probeZ = InstanceID / (ProbeResX * ProbeResY); + + float3 probeUVW = (float3(probeX, probeY, probeZ) + 0.5f) / float3(ProbeResX, ProbeResY, ProbeResZ); + float3 probePos = lerp(SceneMinBounds, SceneMaxBounds, probeUVW); + + float3 cellSizes = (SceneMaxBounds - SceneMinBounds) / float3(ProbeResX, ProbeResZ, ProbeResZ); + float probeSize = 0.15f * min(min(cellSizes.x, cellSizes.y), cellSizes.z); + + float3 vtxPositionWS = (SpherePosition * probeSize) + probePos; + output.PositionCS = mul(float4(vtxPositionWS, 1.0f), ViewProjection); + output.ProbeUVW = probeUVW; + + return output; +} + +//================================================================================================= +// Pixel shader +//================================================================================================= +float4 PS(in PSInput input) : SV_Target0 +{ + float3 output = 0.0f; + + if(ProbeMode == ProbeModes_CubeMap) + { + output = ProbeIrradianceCubeMap.Sample(LinearSampler, float4(input.NormalWS, input.ProbeIdx)).xyz * InvPi; + } + else if(ProbeMode == ProbeModes_AmbientCube) + { + float3 ambientCubeDirs[6] = { float3(1, 0, 0), float3(0, 1, 0), float3(0, 0, 1), float3(-1, 0, 0), float3(0, -1, 0), float3(0, 0, -1) }; + + float weightSum = 0.0f; + + [unroll] + for(uint i = 0; i < 6; ++i) + { + float weight = saturate(dot(input.NormalWS, ambientCubeDirs[i])); + if(weight > 0.0f) + output += ProbeVolumeMaps[i].SampleLevel(LinearSampler, input.ProbeUVW, 0.0f).xyz * weight; + weightSum += weight; + } + + output *= rcp(weightSum) * InvPi; + } + else if(ProbeMode == ProbeModes_L1_SH) + { + SH4Color sh; + + [unroll] + for(uint i = 0; i < 4; ++i) + sh.c[i] = ProbeVolumeMaps[i].SampleLevel(LinearSampler, input.ProbeUVW, 0.0f).xyz; + + output = EvalSH4(input.NormalWS, sh); + } + else if(ProbeMode == ProbeModes_L2_SH) + { + SH9Color sh; + + [unroll] + for(uint i = 0; i < 9; ++i) + sh.c[i] = ProbeVolumeMaps[i].SampleLevel(LinearSampler, input.ProbeUVW, 0.0f).xyz; + + output = EvalSH9(input.NormalWS, sh); + } + + return float4(output, 1.0f); +} \ No newline at end of file diff --git a/BakingLab/VoxelVisualizer.hlsl b/BakingLab/VoxelVisualizer.hlsl new file mode 100644 index 0000000..db6314a --- /dev/null +++ b/BakingLab/VoxelVisualizer.hlsl @@ -0,0 +1,201 @@ +//================================================================================================= +// +// Baking Lab +// by MJP and David Neubelt +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +//================================================================================================= +// Includes +//================================================================================================= +#include "AppSettings.hlsl" + +//================================================================================================= +// Constant buffers +//================================================================================================= +cbuffer Constants : register(b0) +{ + float4x4 ViewProjection; + float3 SceneMinBounds; + float3 SceneMaxBounds; + float3 CameraPos; + float MipVoxelRes; +} + +Texture3D VoxelRadiance : register(t0); +Texture3D VoxelRadianceMips[6] : register(t1); +SamplerState PointSampler : register(s0); + +struct VSOutputGeo +{ + float4 PositionCS : SV_Position; + float3 VoxelRadiance : VOXELRADIANCE; +}; + +//================================================================================================= +// Vertex shader for geometry-based voxel visualization +//================================================================================================= +VSOutputGeo GeoVS(in float3 VertexPosition : POSITION, in uint InstanceID : SV_InstanceID) +{ + const uint voxelIdx = InstanceID; + const uint3 voxelCoord = uint3(voxelIdx % VoxelResolution, + (voxelIdx / VoxelResolution) % VoxelResolution, + voxelIdx / (VoxelResolution * VoxelResolution)); + + float3 voxelRadiance = VoxelRadiance[voxelCoord].xyz; + const float voxelOpacity = VoxelRadiance[voxelCoord].w; + + if(voxelOpacity <= 0.0f) + { + VSOutputGeo output; + output.PositionCS = float4(-10000.0f, -10000.0f, -10000.0f, 1.0f); + output.VoxelRadiance = 0.0f; + return output; + } + + const float3 uvw = float3((voxelCoord.x + 0.5f) / VoxelResolution, + (voxelCoord.y + 0.5f) / VoxelResolution, + (voxelCoord.z + 0.5f) / VoxelResolution); + + const float3 sceneSize = (SceneMaxBounds - SceneMinBounds); + const float3 voxelSize = sceneSize / float(VoxelResolution); + + const float3 voxelCenter = SceneMinBounds + sceneSize * uvw; + const float3 vtxPositionWS = voxelCenter + VertexPosition * voxelSize; + + VSOutputGeo output; + output.PositionCS = mul(float4(vtxPositionWS, 1.0f), ViewProjection); + output.VoxelRadiance = voxelRadiance; + + return output; +} + +//================================================================================================= +// Pixel shader for geometry-based voxel visualization +//================================================================================================= +float4 GeoPS(in VSOutputGeo input) : SV_Target0 +{ + return float4(input.VoxelRadiance, 1.0f); +} + +struct VSOutputRayMarch +{ + float4 PositionCS : SV_Position; + float3 PositionWS : WORLDPOS; +}; + +//================================================================================================= +// Vertex shader for ray-marching voxel visualization +//================================================================================================= +VSOutputRayMarch RayMarchVS(in float3 VertexPosition : POSITION) +{ + float3 vtxPositionWS = lerp(SceneMinBounds, SceneMaxBounds, VertexPosition + 0.5f); + + VSOutputRayMarch output; + output.PositionCS = mul(float4(vtxPositionWS, 1.0f), ViewProjection); + output.PositionWS = vtxPositionWS; + + return output; +} +float IntersectRayBox_(float3 rayOrg, float3 dir, float3 bbmin, float3 bbmax) +{ + float3 invDir = rcp(dir); + float3 d0 = (bbmin - rayOrg) * invDir; + float3 d1 = (bbmax - rayOrg) * invDir; + + float3 v0 = min(d0, d1); + float3 v1 = max(d0, d1); + + float tmin = max(v0.x, max(v0.y, v0.z)); + float tmax = min(v1.x, min(v1.y, v1.z)); + + return tmin; +} + +float IntersectRayBox(float3 rayOrg, float3 dir, float3 bbmin, float3 bbmax) +{ + float3 invDir = rcp(dir); + float3 d0 = (bbmin - rayOrg) * invDir; + float3 d1 = (bbmax - rayOrg) * invDir; + + float3 v0 = min(d0, d1); + float3 v1 = max(d0, d1); + + float tmin = max(v0.x, max(v0.y, v0.z)); + float tmax = min(v1.x, min(v1.y, v1.z)); + + return tmin >= 0.0f ? tmin : tmax; +} + +//================================================================================================= +// Pixel shader for ray-marching voxel visualization +//================================================================================================= +float4 RayMarchPS(in VSOutputRayMarch input) : SV_Target0 +{ + const float voxelRes = MipVoxelRes; + const float3 sceneSize = SceneMaxBounds - SceneMinBounds; + const float voxelSize = 1.0f / voxelRes; + + const float3 pixelPosVoxelSpace = ((input.PositionWS - SceneMinBounds) / sceneSize) * voxelRes; + const float3 cameraPosVoxelSpace = ((CameraPos - SceneMinBounds) / sceneSize) * voxelRes; + const float3 viewDir = normalize(pixelPosVoxelSpace - cameraPosVoxelSpace); + const float bias = voxelSize * 0.25f; + + // const float opacityCorrection = voxelSize / rcp(VoxelResolution); + + float dist = max(IntersectRayBox_(cameraPosVoxelSpace, viewDir, 0.0f, voxelRes), 0.0f); + float3 currPos = cameraPosVoxelSpace + viewDir * (dist + bias); + + const float mipLevel = VoxelVisualizerMipLevel - 1.0f; + + const uint MaxSteps = 1024; + + float3 radiance = 0.0f; + float opacity = 0.0f; + for(uint i = 0; i < MaxSteps; ++i) + { + float3 uvw = currPos / voxelRes; + if(any(abs(uvw * 2.0f - 1.0f) > 1.0001f) || opacity >= 0.999f) + break; + + const float3 currVoxelMin = floor(currPos); + const float3 currVoxelMax = currVoxelMin + 1.0f; + const float3 currVoxelCenter = (currVoxelMin + currVoxelMax) / 2.0f; + + #if FirstMip_ + float4 voxelSample = VoxelRadiance.SampleLevel(PointSampler, uvw, 0.0f); + #else + float3 voxelToPos = currPos - currVoxelCenter; + float largestComponent = max(max(abs(voxelToPos.x), abs(voxelToPos.y)), abs(voxelToPos.z)); + + float4 voxelSample = 0.0f; + if(largestComponent == voxelToPos.x) + voxelSample = VoxelRadianceMips[0].SampleLevel(PointSampler, uvw, mipLevel); + else if(largestComponent == -voxelToPos.x) + voxelSample = VoxelRadianceMips[1].SampleLevel(PointSampler, uvw, mipLevel); + else if(largestComponent == voxelToPos.y) + voxelSample = VoxelRadianceMips[2].SampleLevel(PointSampler, uvw, mipLevel); + else if(largestComponent == -voxelToPos.y) + voxelSample = VoxelRadianceMips[3].SampleLevel(PointSampler, uvw, mipLevel); + else if(largestComponent == voxelToPos.z) + voxelSample = VoxelRadianceMips[4].SampleLevel(PointSampler, uvw, mipLevel); + else if(largestComponent == -voxelToPos.z) + voxelSample = VoxelRadianceMips[5].SampleLevel(PointSampler, uvw, mipLevel); + #endif + + voxelSample.w = saturate(voxelSample.w); + // voxelSample.w = pow(1.0f - voxelSample.w, opacityCorrection); + + radiance += (1.0f - opacity) * voxelSample.xyz; + opacity += (1.0f - opacity) * voxelSample.w; + + const float distToNextVoxel = IntersectRayBox(currPos, viewDir, currVoxelMin, currVoxelMax); + + currPos += viewDir * (distToNextVoxel + bias); + } + + return float4(radiance, opacity); +} diff --git a/Content/EnvMaps/Ennis.shdata b/Content/EnvMaps/Ennis.shdata deleted file mode 100644 index 1399733..0000000 Binary files a/Content/EnvMaps/Ennis.shdata and /dev/null differ diff --git a/Content/EnvMaps/GraceCathedral.shdata b/Content/EnvMaps/GraceCathedral.shdata deleted file mode 100644 index 4de5beb..0000000 --- a/Content/EnvMaps/GraceCathedral.shdata +++ /dev/null @@ -1 +0,0 @@ -øØj?6m?Ý-ä>uj?}‘'?ÍR?pDv>Lë>êW¼=8°`=RE)=AÐ=ÖSØ=Qœ= Uš= ¹ò>( œ>ä´G>P¿¤×¸¾3ù†¾-=‰×<®Ù=÷–¿ èG¿\4¿ \ No newline at end of file diff --git a/Content/EnvMaps/Uffizi.shdata b/Content/EnvMaps/Uffizi.shdata deleted file mode 100644 index 23aa070..0000000 --- a/Content/EnvMaps/Uffizi.shdata +++ /dev/null @@ -1,2 +0,0 @@ -¬šG@i@@�Ó[@L†p@lo@_‹@HËŸ=Ç~¦=F)á=&ݼÆZȼ âþ¼}ØÃ½Ápµ½ƒ[Ò½Hg:>Ô<>Ô¼v>7]4¿ >7¿{ü_¿Æ¹°»2Åp»ª)»ö¹fÀÀ\dÀ6 -…À \ No newline at end of file diff --git a/Content/Textures/SHSpecularA.dds b/Content/Textures/SHSpecularA.dds index 4e54058..c5f7d35 100644 Binary files a/Content/Textures/SHSpecularA.dds and b/Content/Textures/SHSpecularA.dds differ diff --git a/Content/Textures/SHSpecularB.dds b/Content/Textures/SHSpecularB.dds index 7fe55f7..79bece5 100644 Binary files a/Content/Textures/SHSpecularB.dds and b/Content/Textures/SHSpecularB.dds differ diff --git a/Externals/HosekSky/Include/ArHosekSkyModel.c b/Externals/HosekSky/Include/ArHosekSkyModel.c index 17c8880..11dc22c 100644 --- a/Externals/HosekSky/Include/ArHosekSkyModel.c +++ b/Externals/HosekSky/Include/ArHosekSkyModel.c @@ -523,7 +523,7 @@ double arhosekskymodel_radiance( double wavelength ) { - int low_wl = (wavelength - 320.0 ) / 40.0; + int low_wl = (int)((wavelength - 320.0 ) / 40.0); if ( low_wl < 0 || low_wl >= 11 ) return 0.0f; diff --git a/Externals/d3dcompiler_47.dll b/Externals/d3dcompiler_47.dll index 356a777..adf8e21 100644 Binary files a/Externals/d3dcompiler_47.dll and b/Externals/d3dcompiler_47.dll differ diff --git a/SampleFramework11/v1.02/Graphics/Camera.h b/SampleFramework11/v1.02/Graphics/Camera.h index 0268311..51b98ce 100644 --- a/SampleFramework11/v1.02/Graphics/Camera.h +++ b/SampleFramework11/v1.02/Graphics/Camera.h @@ -1,141 +1,145 @@ -//================================================================================================= -// -// MJP's DX11 Sample Framework -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -#pragma once - -#include "..\\PCH.h" -#include "..\\SF11_Math.h" - -namespace SampleFramework11 -{ - -// Abstract base class for camera types -class Camera -{ - -protected: - - Float4x4 view; - Float4x4 projection; - Float4x4 viewProjection; - - Float4x4 world; - Float3 position; - Quaternion orientation; - - float nearZ; - float farZ; - - virtual void CreateProjection() = 0; - void WorldMatrixChanged(); - -public: - - Camera(float nearZ, float farZ); - ~Camera(); - - const Float4x4& ViewMatrix() const { return view; }; - const Float4x4& ProjectionMatrix() const { return projection; }; - const Float4x4& ViewProjectionMatrix() const { return viewProjection; }; - const Float4x4& WorldMatrix() const { return world; }; - const Float3& Position() const { return position; }; - const Quaternion& Orientation() const { return orientation; }; - const float& NearClip() const { return nearZ; }; - const float& FarClip() const { return farZ; }; - - Float3 Forward() const; - Float3 Back() const; - Float3 Up() const; - Float3 Down() const; - Float3 Right() const; - Float3 Left() const; - - void SetLookAt(const Float3& eye, const Float3& lookAt, const Float3& up); - void SetWorldMatrix(const Float4x4& newWorld); - void SetPosition(const Float3& newPosition); - void SetOrientation(const Quaternion& newOrientation); - void SetNearClip(float newNearClip); - void SetFarClip(float newFarClip); - void SetProjection(const Float4x4& newProjection); -}; - -// Camera with an orthographic projection -class OrthographicCamera : public Camera -{ - -protected: - - float xMin; - float xMax; - float yMin; - float yMax; - - virtual void CreateProjection() override; - -public: - - OrthographicCamera(float minX, float minY, float maxX, float maxY, float nearClip, float farClip); - ~OrthographicCamera(); - - float MinX() const { return xMin; }; - float MinY() const { return yMin; }; - float MaxX() const { return xMax; }; - float MaxY() const { return yMax; }; - - void SetMinX(float minX); - void SetMinY(float minY); - void SetMaxX(float maxX); - void SetMaxY(float maxY); -}; - -// Camera with a perspective projection -class PerspectiveCamera : public Camera -{ - -protected: - - float aspect; - float fov; - - virtual void CreateProjection() override; - -public: - - PerspectiveCamera(float aspectRatio, float fieldOfView, float nearClip, float farClip); - ~PerspectiveCamera(); - - float AspectRatio() const { return aspect; }; - float FieldOfView() const { return fov; }; - - void SetAspectRatio(float aspectRatio); - void SetFieldOfView(float fieldOfView); -}; - -// Perspective camera that rotates about Z and Y axes -class FirstPersonCamera : public PerspectiveCamera -{ - -protected: - - float xRot; - float yRot; - -public: - - FirstPersonCamera(float aspectRatio = 16.0f / 9.0f, float fieldOfView = Pi_4, float nearClip = 0.01f, float farClip = 100.0f); - ~FirstPersonCamera(); - - float XRotation() const { return xRot; }; - float YRotation() const { return yRot; }; - - void SetXRotation(float xRotation); - void SetYRotation(float yRotation); -}; - +//================================================================================================= +// +// MJP's DX11 Sample Framework +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +#pragma once + +#include "..\\PCH.h" +#include "..\\SF11_Math.h" + +namespace SampleFramework11 +{ + +// Abstract base class for camera types +class Camera +{ + +protected: + + Float4x4 view; + Float4x4 projection; + Float4x4 viewProjection; + + Float4x4 world; + Float3 position; + Quaternion orientation; + + float nearZ; + float farZ; + + virtual void CreateProjection() = 0; + void WorldMatrixChanged(); + +public: + + Camera(float nearZ, float farZ); + ~Camera(); + + const Float4x4& ViewMatrix() const { return view; }; + const Float4x4& ProjectionMatrix() const { return projection; }; + const Float4x4& ViewProjectionMatrix() const { return viewProjection; }; + const Float4x4& WorldMatrix() const { return world; }; + const Float3& Position() const { return position; }; + const Quaternion& Orientation() const { return orientation; }; + const float& NearClip() const { return nearZ; }; + const float& FarClip() const { return farZ; }; + + Float3 Forward() const; + Float3 Back() const; + Float3 Up() const; + Float3 Down() const; + Float3 Right() const; + Float3 Left() const; + + void SetLookAt(const Float3& eye, const Float3& lookAt, const Float3& up); + void SetWorldMatrix(const Float4x4& newWorld); + void SetPosition(const Float3& newPosition); + void SetOrientation(const Quaternion& newOrientation); + void SetNearClip(float newNearClip); + void SetFarClip(float newFarClip); + void SetProjection(const Float4x4& newProjection); + + virtual bool IsOrthographic() const { return false; } +}; + +// Camera with an orthographic projection +class OrthographicCamera : public Camera +{ + +protected: + + float xMin; + float xMax; + float yMin; + float yMax; + + virtual void CreateProjection() override; + +public: + + OrthographicCamera(float minX, float minY, float maxX, float maxY, float nearClip, float farClip); + ~OrthographicCamera(); + + float MinX() const { return xMin; }; + float MinY() const { return yMin; }; + float MaxX() const { return xMax; }; + float MaxY() const { return yMax; }; + + void SetMinX(float minX); + void SetMinY(float minY); + void SetMaxX(float maxX); + void SetMaxY(float maxY); + + bool IsOrthographic() const override { return true; } +}; + +// Camera with a perspective projection +class PerspectiveCamera : public Camera +{ + +protected: + + float aspect; + float fov; + + virtual void CreateProjection() override; + +public: + + PerspectiveCamera(float aspectRatio, float fieldOfView, float nearClip, float farClip); + ~PerspectiveCamera(); + + float AspectRatio() const { return aspect; }; + float FieldOfView() const { return fov; }; + + void SetAspectRatio(float aspectRatio); + void SetFieldOfView(float fieldOfView); +}; + +// Perspective camera that rotates about Z and Y axes +class FirstPersonCamera : public PerspectiveCamera +{ + +protected: + + float xRot; + float yRot; + +public: + + FirstPersonCamera(float aspectRatio = 16.0f / 9.0f, float fieldOfView = Pi_4, float nearClip = 0.01f, float farClip = 100.0f); + ~FirstPersonCamera(); + + float XRotation() const { return xRot; }; + float YRotation() const { return yRot; }; + + void SetXRotation(float xRotation); + void SetYRotation(float yRotation); +}; + } \ No newline at end of file diff --git a/SampleFramework11/v1.02/Graphics/DeviceManager.cpp b/SampleFramework11/v1.02/Graphics/DeviceManager.cpp index 0d626d0..093aa4c 100644 --- a/SampleFramework11/v1.02/Graphics/DeviceManager.cpp +++ b/SampleFramework11/v1.02/Graphics/DeviceManager.cpp @@ -1,251 +1,253 @@ -//================================================================================================= -// -// MJP's DX11 Sample Framework -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -#include "PCH.h" - -#include "DeviceManager.h" -#include "..\\Exceptions.h" -#include "..\\Utility.h" - -using std::wstring; - -#if _DEBUG - #define UseDebugDevice_ 1 - #define BreakOnDXError_ (UseDebugDevice_ && 1) -#else - #define UseDebugDevice_ 0 - #define BreakOnDXError_ 0 -#endif - -namespace SampleFramework11 -{ - -DeviceManager::DeviceManager() : backBufferFormat(DXGI_FORMAT_R8G8B8A8_UNORM_SRGB), - backBufferWidth(1280), - backBufferHeight(720), - msCount(1), - msQuality(0), - fullScreen(false), - featureLevel(D3D_FEATURE_LEVEL_11_0), - minFeatureLevel(D3D_FEATURE_LEVEL_10_0), - vsync(true), - numVSYNCIntervals(1) -{ - refreshRate.Numerator = 60; - refreshRate.Denominator = 1; - - // Try to figure out if we should default to 1280x720 or 1920x1080 - POINT point; - point.x = 0; - point.y = 0; - HMONITOR monitor = MonitorFromPoint(point, MONITOR_DEFAULTTOPRIMARY); - if(monitor != 0) - { - MONITORINFOEX info; - ZeroMemory(&info, sizeof(info)); - info.cbSize = sizeof(MONITORINFOEX); - if(GetMonitorInfo(monitor, &info) != 0) - { - int32 width = info.rcWork.right - info.rcWork.left; - int32 height = info.rcWork.bottom - info.rcWork.top; - if(width > 1920 && height > 1080) - { - backBufferWidth = 1920; - backBufferHeight = 1080; - } - } - } -} - -DeviceManager::~DeviceManager() -{ - if(immediateContext) - { - immediateContext->ClearState(); - immediateContext->Flush(); - } -} - -void DeviceManager::Initialize(HWND outputWindow) -{ - CheckForSuitableOutput(); - - DXGI_SWAP_CHAIN_DESC desc; - ZeroMemory(&desc, sizeof(DXGI_SWAP_CHAIN_DESC)); - - if(fullScreen) - { - PrepareFullScreenSettings(); - } - else - { - refreshRate.Numerator = 60; - refreshRate.Denominator = 1; - } - - desc.BufferCount = 2; - desc.BufferDesc.Format = backBufferFormat; - desc.BufferDesc.Width = backBufferWidth; - desc.BufferDesc.Height = backBufferHeight; - desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; - desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; - desc.BufferDesc.RefreshRate = refreshRate; - desc.SampleDesc.Count = msCount; - desc.SampleDesc.Quality = msQuality; - desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; - desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; - desc.OutputWindow = outputWindow; - desc.Windowed = !fullScreen; - - uint32 flags = D3D11_CREATE_DEVICE_SINGLETHREADED; - #if UseDebugDevice_ - flags |= D3D11_CREATE_DEVICE_DEBUG; - #endif - - DXCall(D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, flags, - NULL, 0, D3D11_SDK_VERSION, &desc, &swapChain, - &device, NULL, &immediateContext)); - - featureLevel = device->GetFeatureLevel(); - - if(featureLevel < minFeatureLevel) - { - wstring majorLevel = ToString(minFeatureLevel >> 12); - wstring minorLevel = ToString((minFeatureLevel >> 8) & 0xF); - throw Exception(L"The device doesn't support the minimum feature level required to run this sample (DX" + majorLevel + L"." + minorLevel + L")"); - } - - if(BreakOnDXError_ && D3DPERF_GetStatus() == 0) - { - ID3D11InfoQueuePtr infoQueue; - DXCall(device->QueryInterface(__uuidof(ID3D11InfoQueue), reinterpret_cast(&infoQueue))); - infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING, TRUE); - infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, TRUE); - } - - AfterReset(); -} - -void DeviceManager::AfterReset() -{ - DXCall(swapChain->GetBuffer(0, __uuidof(bbTexture), reinterpret_cast(&bbTexture))); - DXCall(device->CreateRenderTargetView(bbTexture, NULL, &bbRTView)); - - // Set default render targets - immediateContext->OMSetRenderTargets(1, &(bbRTView.GetInterfacePtr()), NULL); - - // Setup the viewport - D3D11_VIEWPORT vp; - vp.Width = static_cast(backBufferWidth); - vp.Height = static_cast(backBufferHeight); - vp.MinDepth = 0.0f; - vp.MaxDepth = 1.0f; - vp.TopLeftX = 0; - vp.TopLeftY = 0; - immediateContext->RSSetViewports(1, &vp); -} - -void DeviceManager::CheckForSuitableOutput() -{ - HRESULT hr = CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast(&factory)); - if(FAILED(hr)) - throw Exception(L"Unable to create a DXGI 1.1 device.\n " - L"Make sure that your OS and driver support DirectX 11"); - - // Look for an adapter that supports D3D11 - IDXGIAdapter1Ptr curAdapter; - uint32 adapterIdx = 0; - LARGE_INTEGER umdVersion; - while(!adapter && SUCCEEDED(factory->EnumAdapters1(0, &adapter))) - if(SUCCEEDED(adapter->CheckInterfaceSupport(__uuidof(ID3D11Device), &umdVersion))) - adapter = curAdapter; - - if(!adapter) - throw Exception(L"Unable to locate a DXGI 1.1 adapter that supports a D3D11 device.\n" - L"Make sure that your OS and driver support DirectX 11"); - - // We'll just use the first output - DXCall(adapter->EnumOutputs(0, &output)); -} - -void DeviceManager::PrepareFullScreenSettings() -{ - Assert_(output); - - // Have the Output look for the closest matching mode - DXGI_MODE_DESC desiredMode; - desiredMode.Format = backBufferFormat; - desiredMode.Width = backBufferWidth; - desiredMode.Height = backBufferHeight; - desiredMode.RefreshRate.Numerator = 0; - desiredMode.RefreshRate.Denominator = 0; - desiredMode.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; - desiredMode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; - - DXGI_MODE_DESC closestMatch; - DXCall(output->FindClosestMatchingMode(&desiredMode, &closestMatch, device.GetInterfacePtr())); - - backBufferFormat = closestMatch.Format; - backBufferWidth = closestMatch.Width; - backBufferHeight = closestMatch.Height; - refreshRate = closestMatch.RefreshRate; -} - -void DeviceManager::Reset() -{ - Assert_(swapChain); - - // Release all references - if(bbTexture) - bbTexture.Release(); - - if(bbRTView) - bbRTView.Release(); - - immediateContext->ClearState(); - - if(fullScreen) - PrepareFullScreenSettings(); - else - { - refreshRate.Numerator = 60; - refreshRate.Denominator = 1; - } - - DXCall(swapChain->SetFullscreenState(fullScreen, NULL)); - - DXCall(swapChain->ResizeBuffers(2, backBufferWidth, backBufferHeight, - backBufferFormat, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH)); - - if(fullScreen) - { - DXGI_MODE_DESC mode; - mode.Format = backBufferFormat; - mode.Width = backBufferWidth; - mode.Height = backBufferHeight; - mode.RefreshRate.Numerator = 0; - mode.RefreshRate.Denominator = 0; - mode.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; - mode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; - DXCall(swapChain->ResizeTarget(&mode)); - } - - AfterReset(); -} - -void DeviceManager::Present() -{ - Assert_(device); - - uint32 interval = vsync ? numVSYNCIntervals : 0; - DXCall(swapChain->Present(interval, 0)); -} - +//================================================================================================= +// +// MJP's DX11 Sample Framework +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +#include "PCH.h" + +#include "DeviceManager.h" +#include "..\\Exceptions.h" +#include "..\\Utility.h" + +using std::wstring; + +#if _DEBUG + #define UseDebugDevice_ 1 + #define BreakOnDXError_ (UseDebugDevice_ && 1) +#else + #define UseDebugDevice_ 0 + #define BreakOnDXError_ 0 +#endif + +namespace SampleFramework11 +{ + +DeviceManager::DeviceManager() : backBufferFormat(DXGI_FORMAT_R8G8B8A8_UNORM_SRGB), + backBufferWidth(1280), + backBufferHeight(720), + msCount(1), + msQuality(0), + fullScreen(false), + featureLevel(D3D_FEATURE_LEVEL_11_1), + minFeatureLevel(D3D_FEATURE_LEVEL_11_1), + vsync(true), + numVSYNCIntervals(1) +{ + refreshRate.Numerator = 60; + refreshRate.Denominator = 1; + + // Try to figure out if we should default to 1280x720 or 1920x1080 + POINT point; + point.x = 0; + point.y = 0; + HMONITOR monitor = MonitorFromPoint(point, MONITOR_DEFAULTTOPRIMARY); + if(monitor != 0) + { + MONITORINFOEX info; + ZeroMemory(&info, sizeof(info)); + info.cbSize = sizeof(MONITORINFOEX); + if(GetMonitorInfo(monitor, &info) != 0) + { + int32 width = info.rcWork.right - info.rcWork.left; + int32 height = info.rcWork.bottom - info.rcWork.top; + if(width > 1920 && height > 1080) + { + backBufferWidth = 1920; + backBufferHeight = 1080; + } + } + } +} + +DeviceManager::~DeviceManager() +{ + if(immediateContext) + { + immediateContext->ClearState(); + immediateContext->Flush(); + } +} + +void DeviceManager::Initialize(HWND outputWindow) +{ + CheckForSuitableOutput(); + + DXGI_SWAP_CHAIN_DESC desc; + ZeroMemory(&desc, sizeof(DXGI_SWAP_CHAIN_DESC)); + + if(fullScreen) + { + PrepareFullScreenSettings(); + } + else + { + refreshRate.Numerator = 60; + refreshRate.Denominator = 1; + } + + desc.BufferCount = 2; + desc.BufferDesc.Format = backBufferFormat; + desc.BufferDesc.Width = backBufferWidth; + desc.BufferDesc.Height = backBufferHeight; + desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; + desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; + desc.BufferDesc.RefreshRate = refreshRate; + desc.SampleDesc.Count = msCount; + desc.SampleDesc.Quality = msQuality; + desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; + desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + desc.OutputWindow = outputWindow; + desc.Windowed = !fullScreen; + + uint32 flags = D3D11_CREATE_DEVICE_SINGLETHREADED; + #if UseDebugDevice_ + flags |= D3D11_CREATE_DEVICE_DEBUG; + #endif + + D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_12_1 }; + + DXCall(D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, flags, + featureLevels, ArraySize_(featureLevels), D3D11_SDK_VERSION, &desc, &swapChain, + &device, NULL, &immediateContext)); + + featureLevel = device->GetFeatureLevel(); + + if(featureLevel < minFeatureLevel) + { + wstring majorLevel = ToString(minFeatureLevel >> 12); + wstring minorLevel = ToString((minFeatureLevel >> 8) & 0xF); + throw Exception(L"The device doesn't support the minimum feature level required to run this sample (DX" + majorLevel + L"." + minorLevel + L")"); + } + + if(BreakOnDXError_ && D3DPERF_GetStatus() == 0) + { + ID3D11InfoQueuePtr infoQueue; + DXCall(device->QueryInterface(__uuidof(ID3D11InfoQueue), reinterpret_cast(&infoQueue))); + infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING, TRUE); + infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, TRUE); + } + + AfterReset(); +} + +void DeviceManager::AfterReset() +{ + DXCall(swapChain->GetBuffer(0, __uuidof(bbTexture), reinterpret_cast(&bbTexture))); + DXCall(device->CreateRenderTargetView(bbTexture, NULL, &bbRTView)); + + // Set default render targets + immediateContext->OMSetRenderTargets(1, &(bbRTView.GetInterfacePtr()), NULL); + + // Setup the viewport + D3D11_VIEWPORT vp; + vp.Width = static_cast(backBufferWidth); + vp.Height = static_cast(backBufferHeight); + vp.MinDepth = 0.0f; + vp.MaxDepth = 1.0f; + vp.TopLeftX = 0; + vp.TopLeftY = 0; + immediateContext->RSSetViewports(1, &vp); +} + +void DeviceManager::CheckForSuitableOutput() +{ + HRESULT hr = CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast(&factory)); + if(FAILED(hr)) + throw Exception(L"Unable to create a DXGI 1.1 device.\n " + L"Make sure that your OS and driver support DirectX 11"); + + // Look for an adapter that supports D3D11 + IDXGIAdapter1Ptr curAdapter; + uint32 adapterIdx = 0; + LARGE_INTEGER umdVersion; + while(!adapter && SUCCEEDED(factory->EnumAdapters1(0, &adapter))) + if(SUCCEEDED(adapter->CheckInterfaceSupport(__uuidof(ID3D11Device), &umdVersion))) + adapter = curAdapter; + + if(!adapter) + throw Exception(L"Unable to locate a DXGI 1.1 adapter that supports a D3D11 device.\n" + L"Make sure that your OS and driver support DirectX 11"); + + // We'll just use the first output + DXCall(adapter->EnumOutputs(0, &output)); +} + +void DeviceManager::PrepareFullScreenSettings() +{ + Assert_(output); + + // Have the Output look for the closest matching mode + DXGI_MODE_DESC desiredMode; + desiredMode.Format = backBufferFormat; + desiredMode.Width = backBufferWidth; + desiredMode.Height = backBufferHeight; + desiredMode.RefreshRate.Numerator = 0; + desiredMode.RefreshRate.Denominator = 0; + desiredMode.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; + desiredMode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; + + DXGI_MODE_DESC closestMatch; + DXCall(output->FindClosestMatchingMode(&desiredMode, &closestMatch, device.GetInterfacePtr())); + + backBufferFormat = closestMatch.Format; + backBufferWidth = closestMatch.Width; + backBufferHeight = closestMatch.Height; + refreshRate = closestMatch.RefreshRate; +} + +void DeviceManager::Reset() +{ + Assert_(swapChain); + + // Release all references + if(bbTexture) + bbTexture.Release(); + + if(bbRTView) + bbRTView.Release(); + + immediateContext->ClearState(); + + if(fullScreen) + PrepareFullScreenSettings(); + else + { + refreshRate.Numerator = 60; + refreshRate.Denominator = 1; + } + + DXCall(swapChain->SetFullscreenState(fullScreen, NULL)); + + DXCall(swapChain->ResizeBuffers(2, backBufferWidth, backBufferHeight, + backBufferFormat, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH)); + + if(fullScreen) + { + DXGI_MODE_DESC mode; + mode.Format = backBufferFormat; + mode.Width = backBufferWidth; + mode.Height = backBufferHeight; + mode.RefreshRate.Numerator = 0; + mode.RefreshRate.Denominator = 0; + mode.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; + mode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; + DXCall(swapChain->ResizeTarget(&mode)); + } + + AfterReset(); +} + +void DeviceManager::Present() +{ + Assert_(device); + + uint32 interval = vsync ? numVSYNCIntervals : 0; + DXCall(swapChain->Present(interval, 0)); +} + } \ No newline at end of file diff --git a/SampleFramework11/v1.02/Graphics/DeviceStates.cpp b/SampleFramework11/v1.02/Graphics/DeviceStates.cpp index 144307e..e57022f 100644 --- a/SampleFramework11/v1.02/Graphics/DeviceStates.cpp +++ b/SampleFramework11/v1.02/Graphics/DeviceStates.cpp @@ -1,658 +1,683 @@ -//================================================================================================= -// -// MJP's DX11 Sample Framework -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -#include "PCH.h" - -#include "DeviceStates.h" -#include "..\\Utility.h" - -namespace SampleFramework11 -{ - -void BlendStates::Initialize(ID3D11Device* device) -{ - DXCall(device->CreateBlendState(&BlendDisabledDesc(), &blendDisabled)); - DXCall(device->CreateBlendState(&AdditiveBlendDesc(), &additiveBlend)); - DXCall(device->CreateBlendState(&AlphaBlendDesc(), &alphaBlend)); - DXCall(device->CreateBlendState(&PreMultipliedAlphaBlendDesc(), &pmAlphaBlend)); - DXCall(device->CreateBlendState(&ColorWriteDisabledDesc(), &noColor)); - DXCall(device->CreateBlendState(&AlphaToCoverageDesc(), &alphaToCoverage)); - DXCall(device->CreateBlendState(&OpacityBlendDesc(), &opacityBlend)); -} - -D3D11_BLEND_DESC BlendStates::BlendDisabledDesc() -{ - D3D11_BLEND_DESC blendDesc; - blendDesc.AlphaToCoverageEnable = false; - blendDesc.IndependentBlendEnable = false; - for(UINT i = 0; i < 8; ++i) - { - blendDesc.RenderTarget[i].BlendEnable = false; - blendDesc.RenderTarget[i].BlendOp = D3D11_BLEND_OP_ADD; - blendDesc.RenderTarget[i].BlendOpAlpha = D3D11_BLEND_OP_ADD; - blendDesc.RenderTarget[i].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; - blendDesc.RenderTarget[i].DestBlendAlpha = D3D11_BLEND_ONE; - blendDesc.RenderTarget[i].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; - blendDesc.RenderTarget[i].SrcBlend = D3D11_BLEND_SRC_ALPHA; - blendDesc.RenderTarget[i].SrcBlendAlpha = D3D11_BLEND_ONE; - } - - return blendDesc; -} - -D3D11_BLEND_DESC BlendStates::AdditiveBlendDesc() -{ - D3D11_BLEND_DESC blendDesc; - blendDesc.AlphaToCoverageEnable = false; - blendDesc.IndependentBlendEnable = false; - for (uint32 i = 0; i < 8; ++i) - { - blendDesc.RenderTarget[i].BlendEnable = true; - blendDesc.RenderTarget[i].BlendOp = D3D11_BLEND_OP_ADD; - blendDesc.RenderTarget[i].BlendOpAlpha = D3D11_BLEND_OP_ADD; - blendDesc.RenderTarget[i].DestBlend = D3D11_BLEND_ONE; - blendDesc.RenderTarget[i].DestBlendAlpha = D3D11_BLEND_ONE; - blendDesc.RenderTarget[i].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; - blendDesc.RenderTarget[i].SrcBlend = D3D11_BLEND_ONE; - blendDesc.RenderTarget[i].SrcBlendAlpha = D3D11_BLEND_ONE; - } - - return blendDesc; -} - -D3D11_BLEND_DESC BlendStates::AlphaBlendDesc() -{ - D3D11_BLEND_DESC blendDesc; - blendDesc.AlphaToCoverageEnable = false; - blendDesc.IndependentBlendEnable = true; - for (uint32 i = 0; i < 8; ++i) - { - blendDesc.RenderTarget[i].BlendEnable = true; - blendDesc.RenderTarget[i].BlendOp = D3D11_BLEND_OP_ADD; - blendDesc.RenderTarget[i].BlendOpAlpha = D3D11_BLEND_OP_ADD; - blendDesc.RenderTarget[i].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; - blendDesc.RenderTarget[i].DestBlendAlpha = D3D11_BLEND_ONE; - blendDesc.RenderTarget[i].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; - blendDesc.RenderTarget[i].SrcBlend = D3D11_BLEND_SRC_ALPHA; - blendDesc.RenderTarget[i].SrcBlendAlpha = D3D11_BLEND_ONE; - } - - blendDesc.RenderTarget[0].BlendEnable = true; - - return blendDesc; -} - -D3D11_BLEND_DESC BlendStates::PreMultipliedAlphaBlendDesc() -{ - D3D11_BLEND_DESC blendDesc; - blendDesc.AlphaToCoverageEnable = false; - blendDesc.IndependentBlendEnable = false; - for (uint32 i = 0; i < 8; ++i) - { - blendDesc.RenderTarget[i].BlendEnable = false; - blendDesc.RenderTarget[i].BlendOp = D3D11_BLEND_OP_ADD; - blendDesc.RenderTarget[i].BlendOpAlpha = D3D11_BLEND_OP_ADD; - blendDesc.RenderTarget[i].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; - blendDesc.RenderTarget[i].DestBlendAlpha = D3D11_BLEND_ONE; - blendDesc.RenderTarget[i].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; - blendDesc.RenderTarget[i].SrcBlend = D3D11_BLEND_ONE; - blendDesc.RenderTarget[i].SrcBlendAlpha = D3D11_BLEND_ONE; - } - - return blendDesc; -} - -D3D11_BLEND_DESC BlendStates::ColorWriteDisabledDesc() -{ - D3D11_BLEND_DESC blendDesc; - blendDesc.AlphaToCoverageEnable = false; - blendDesc.IndependentBlendEnable = false; - for (uint32 i = 0; i < 8; ++i) - { - blendDesc.RenderTarget[i].BlendEnable = false; - blendDesc.RenderTarget[i].BlendOp = D3D11_BLEND_OP_ADD; - blendDesc.RenderTarget[i].BlendOpAlpha = D3D11_BLEND_OP_ADD; - blendDesc.RenderTarget[i].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; - blendDesc.RenderTarget[i].DestBlendAlpha = D3D11_BLEND_ONE; - blendDesc.RenderTarget[i].RenderTargetWriteMask = 0; - blendDesc.RenderTarget[i].SrcBlend = D3D11_BLEND_SRC_ALPHA; - blendDesc.RenderTarget[i].SrcBlendAlpha = D3D11_BLEND_ONE; - } - - return blendDesc; -} - -D3D11_BLEND_DESC BlendStates::AlphaToCoverageDesc() -{ - D3D11_BLEND_DESC blendDesc; - blendDesc.AlphaToCoverageEnable = true; - blendDesc.IndependentBlendEnable = false; - for (uint32 i = 0; i < 8; ++i) - { - blendDesc.RenderTarget[i].BlendEnable = false; - blendDesc.RenderTarget[i].BlendOp = D3D11_BLEND_OP_ADD; - blendDesc.RenderTarget[i].BlendOpAlpha = D3D11_BLEND_OP_ADD; - blendDesc.RenderTarget[i].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; - blendDesc.RenderTarget[i].DestBlendAlpha = D3D11_BLEND_ONE; - blendDesc.RenderTarget[i].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; - blendDesc.RenderTarget[i].SrcBlend = D3D11_BLEND_SRC_ALPHA; - blendDesc.RenderTarget[i].SrcBlendAlpha = D3D11_BLEND_ONE; - } - - return blendDesc; -} - -D3D11_BLEND_DESC BlendStates::OpacityBlendDesc() -{ - D3D11_BLEND_DESC blendDesc; - blendDesc.AlphaToCoverageEnable = false; - blendDesc.IndependentBlendEnable = false; - for (uint32 i = 0; i < 8; ++i) - { - blendDesc.RenderTarget[i].BlendEnable = true; - blendDesc.RenderTarget[i].BlendOp = D3D11_BLEND_OP_ADD; - blendDesc.RenderTarget[i].BlendOpAlpha = D3D11_BLEND_OP_ADD; - blendDesc.RenderTarget[i].DestBlend = D3D11_BLEND_INV_SRC1_COLOR; - blendDesc.RenderTarget[i].DestBlendAlpha = D3D11_BLEND_ONE; - blendDesc.RenderTarget[i].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; - blendDesc.RenderTarget[i].SrcBlend = D3D11_BLEND_ONE; - blendDesc.RenderTarget[i].SrcBlendAlpha = D3D11_BLEND_ONE; - } - - return blendDesc; -} - -void RasterizerStates::Initialize(ID3D11Device* device) -{ - DXCall(device->CreateRasterizerState(&NoCullDesc(), &noCull)); - DXCall(device->CreateRasterizerState(&FrontFaceCullDesc(), &cullFrontFaces)); - DXCall(device->CreateRasterizerState(&FrontFaceCullScissorDesc(), &cullFrontFacesScissor)); - DXCall(device->CreateRasterizerState(&BackFaceCullDesc(), &cullBackFaces)); - DXCall(device->CreateRasterizerState(&BackFaceCullScissorDesc(), &cullBackFacesScissor)); - DXCall(device->CreateRasterizerState(&BackFaceCullNoZClipDesc(), &cullBackFacesNoZClip)); - DXCall(device->CreateRasterizerState(&NoCullNoMSDesc(), &noCullNoMS)); - DXCall(device->CreateRasterizerState(&NoCullScissorDesc(), &noCullScissor)); - DXCall(device->CreateRasterizerState(&WireframeDesc(), &wireframe)); -} - -D3D11_RASTERIZER_DESC RasterizerStates::NoCullDesc() -{ - D3D11_RASTERIZER_DESC rastDesc; - - rastDesc.AntialiasedLineEnable = false; - rastDesc.CullMode = D3D11_CULL_NONE; - rastDesc.DepthBias = 0; - rastDesc.DepthBiasClamp = 0.0f; - rastDesc.DepthClipEnable = true; - rastDesc.FillMode = D3D11_FILL_SOLID; - rastDesc.FrontCounterClockwise = false; - rastDesc.MultisampleEnable = true; - rastDesc.ScissorEnable = false; - rastDesc.SlopeScaledDepthBias = 0; - - return rastDesc; -} - -D3D11_RASTERIZER_DESC RasterizerStates::FrontFaceCullDesc() -{ - D3D11_RASTERIZER_DESC rastDesc; - - rastDesc.AntialiasedLineEnable = false; - rastDesc.CullMode = D3D11_CULL_FRONT; - rastDesc.DepthBias = 0; - rastDesc.DepthBiasClamp = 0.0f; - rastDesc.DepthClipEnable = true; - rastDesc.FillMode = D3D11_FILL_SOLID; - rastDesc.FrontCounterClockwise = false; - rastDesc.MultisampleEnable = true; - rastDesc.ScissorEnable = false; - rastDesc.SlopeScaledDepthBias = 0; - - return rastDesc; -} - -D3D11_RASTERIZER_DESC RasterizerStates::FrontFaceCullScissorDesc() -{ - D3D11_RASTERIZER_DESC rastDesc; - - rastDesc.AntialiasedLineEnable = false; - rastDesc.CullMode = D3D11_CULL_FRONT; - rastDesc.DepthBias = 0; - rastDesc.DepthBiasClamp = 0.0f; - rastDesc.DepthClipEnable = true; - rastDesc.FillMode = D3D11_FILL_SOLID; - rastDesc.FrontCounterClockwise = true; - rastDesc.MultisampleEnable = true; - rastDesc.ScissorEnable = true; - rastDesc.SlopeScaledDepthBias = 0; - - return rastDesc; -} - -D3D11_RASTERIZER_DESC RasterizerStates::BackFaceCullDesc() -{ - D3D11_RASTERIZER_DESC rastDesc; - - rastDesc.AntialiasedLineEnable = false; - rastDesc.CullMode = D3D11_CULL_BACK; - rastDesc.DepthBias = 0; - rastDesc.DepthBiasClamp = 0.0f; - rastDesc.DepthClipEnable = true; - rastDesc.FillMode = D3D11_FILL_SOLID; - rastDesc.FrontCounterClockwise = false; - rastDesc.MultisampleEnable = true; - rastDesc.ScissorEnable = false; - rastDesc.SlopeScaledDepthBias = 0; - - return rastDesc; -} - -D3D11_RASTERIZER_DESC RasterizerStates::BackFaceCullScissorDesc() -{ - D3D11_RASTERIZER_DESC rastDesc; - - rastDesc.AntialiasedLineEnable = false; - rastDesc.CullMode = D3D11_CULL_BACK; - rastDesc.DepthBias = 0; - rastDesc.DepthBiasClamp = 0.0f; - rastDesc.DepthClipEnable = true; - rastDesc.FillMode = D3D11_FILL_SOLID; - rastDesc.FrontCounterClockwise = false; - rastDesc.MultisampleEnable = true; - rastDesc.ScissorEnable = true; - rastDesc.SlopeScaledDepthBias = 0; - - return rastDesc; -} - -D3D11_RASTERIZER_DESC RasterizerStates::BackFaceCullNoZClipDesc() -{ - D3D11_RASTERIZER_DESC rastDesc; - - rastDesc.AntialiasedLineEnable = false; - rastDesc.CullMode = D3D11_CULL_BACK; - rastDesc.DepthBias = 0; - rastDesc.DepthBiasClamp = 0.0f; - rastDesc.DepthClipEnable = false; - rastDesc.FillMode = D3D11_FILL_SOLID; - rastDesc.FrontCounterClockwise = false; - rastDesc.MultisampleEnable = true; - rastDesc.ScissorEnable = false; - rastDesc.SlopeScaledDepthBias = 0; - - return rastDesc; -} - -D3D11_RASTERIZER_DESC RasterizerStates::NoCullNoMSDesc() -{ - D3D11_RASTERIZER_DESC rastDesc; - - rastDesc.AntialiasedLineEnable = false; - rastDesc.CullMode = D3D11_CULL_NONE; - rastDesc.DepthBias = 0; - rastDesc.DepthBiasClamp = 0.0f; - rastDesc.DepthClipEnable = true; - rastDesc.FillMode = D3D11_FILL_SOLID; - rastDesc.FrontCounterClockwise = false; - rastDesc.MultisampleEnable = false; - rastDesc.ScissorEnable = false; - rastDesc.SlopeScaledDepthBias = 0; - - return rastDesc; -} - -D3D11_RASTERIZER_DESC RasterizerStates::NoCullScissorDesc() -{ - D3D11_RASTERIZER_DESC rastDesc; - - rastDesc.AntialiasedLineEnable = false; - rastDesc.CullMode = D3D11_CULL_NONE; - rastDesc.DepthBias = 0; - rastDesc.DepthBiasClamp = 0.0f; - rastDesc.DepthClipEnable = true; - rastDesc.FillMode = D3D11_FILL_SOLID; - rastDesc.FrontCounterClockwise = false; - rastDesc.MultisampleEnable = true; - rastDesc.ScissorEnable = true; - rastDesc.SlopeScaledDepthBias = 0; - - return rastDesc; -} - -D3D11_RASTERIZER_DESC RasterizerStates::WireframeDesc() -{ - D3D11_RASTERIZER_DESC rastDesc; - - rastDesc.AntialiasedLineEnable = false; - rastDesc.CullMode = D3D11_CULL_NONE; - rastDesc.DepthBias = 0; - rastDesc.DepthBiasClamp = 0.0f; - rastDesc.DepthClipEnable = true; - rastDesc.FillMode = D3D11_FILL_WIREFRAME; - rastDesc.FrontCounterClockwise = false; - rastDesc.MultisampleEnable = true; - rastDesc.ScissorEnable = false; - rastDesc.SlopeScaledDepthBias = 0; - - return rastDesc; -} - -void DepthStencilStates::Initialize(ID3D11Device* device) -{ - DXCall(device->CreateDepthStencilState(&DepthDisabledDesc(), &depthDisabled)); - DXCall(device->CreateDepthStencilState(&DepthEnabledDesc(), &depthEnabled)); - DXCall(device->CreateDepthStencilState(&ReverseDepthEnabledDesc(), &revDepthEnabled)); - DXCall(device->CreateDepthStencilState(&DepthWriteEnabledDesc(), &depthWriteEnabled)); - DXCall(device->CreateDepthStencilState(&ReverseDepthWriteEnabledDesc(), &revDepthWriteEnabled)); - DXCall(device->CreateDepthStencilState(&DepthStencilWriteEnabledDesc(), &depthStencilWriteEnabled)); - DXCall(device->CreateDepthStencilState(&StencilEnabledDesc(), &stencilEnabled)); -} - -D3D11_DEPTH_STENCIL_DESC DepthStencilStates::DepthDisabledDesc() -{ - D3D11_DEPTH_STENCIL_DESC dsDesc; - dsDesc.DepthEnable = false; - dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; - dsDesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL; - dsDesc.StencilEnable = false; - dsDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; - dsDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; - dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; - dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; - dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; - dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; - dsDesc.BackFace = dsDesc.FrontFace; - - return dsDesc; -} - -D3D11_DEPTH_STENCIL_DESC DepthStencilStates::DepthEnabledDesc() -{ - D3D11_DEPTH_STENCIL_DESC dsDesc; - dsDesc.DepthEnable = true; - dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; - dsDesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL; - dsDesc.StencilEnable = false; - dsDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; - dsDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; - dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; - dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; - dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; - dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; - dsDesc.BackFace = dsDesc.FrontFace; - - return dsDesc; -} - -D3D11_DEPTH_STENCIL_DESC DepthStencilStates::ReverseDepthEnabledDesc() -{ - D3D11_DEPTH_STENCIL_DESC dsDesc; - dsDesc.DepthEnable = true; - dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; - dsDesc.DepthFunc = D3D11_COMPARISON_GREATER_EQUAL; - dsDesc.StencilEnable = false; - dsDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; - dsDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; - dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; - dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; - dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; - dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; - dsDesc.BackFace = dsDesc.FrontFace; - - return dsDesc; -} - -D3D11_DEPTH_STENCIL_DESC DepthStencilStates::DepthWriteEnabledDesc() -{ - D3D11_DEPTH_STENCIL_DESC dsDesc; - dsDesc.DepthEnable = true; - dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; - dsDesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL; - dsDesc.StencilEnable = false; - dsDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; - dsDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; - dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; - dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; - dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; - dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; - dsDesc.BackFace = dsDesc.FrontFace; - - return dsDesc; -} - -D3D11_DEPTH_STENCIL_DESC DepthStencilStates::ReverseDepthWriteEnabledDesc() -{ - D3D11_DEPTH_STENCIL_DESC dsDesc; - dsDesc.DepthEnable = true; - dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; - dsDesc.DepthFunc = D3D11_COMPARISON_GREATER_EQUAL; - dsDesc.StencilEnable = false; - dsDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; - dsDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; - dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; - dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; - dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; - dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; - dsDesc.BackFace = dsDesc.FrontFace; - - return dsDesc; -} - -D3D11_DEPTH_STENCIL_DESC DepthStencilStates::DepthStencilWriteEnabledDesc() -{ - D3D11_DEPTH_STENCIL_DESC dsDesc; - dsDesc.DepthEnable = true; - dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; - dsDesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL; - dsDesc.StencilEnable = true; - dsDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; - dsDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; - dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; - dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; - dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; - dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; - dsDesc.BackFace = dsDesc.FrontFace; - - return dsDesc; -} - -D3D11_DEPTH_STENCIL_DESC DepthStencilStates::StencilEnabledDesc() -{ - D3D11_DEPTH_STENCIL_DESC dsDesc; - dsDesc.DepthEnable = true; - dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; - dsDesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL; - dsDesc.StencilEnable = true; - dsDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; - dsDesc.StencilWriteMask = 0; - dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; - dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; - dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; - dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_EQUAL; - dsDesc.BackFace = dsDesc.FrontFace; - - return dsDesc; -} - -void SamplerStates::Initialize(ID3D11Device* device) -{ - DXCall(device->CreateSamplerState(&LinearDesc(), &linear)); - DXCall(device->CreateSamplerState(&LinearClampDesc(), &linearClamp)); - DXCall(device->CreateSamplerState(&LinearBorderDesc(), &linearBorder)); - DXCall(device->CreateSamplerState(&PointDesc(), &point)); - DXCall(device->CreateSamplerState(&AnisotropicDesc(), &anisotropic)); - DXCall(device->CreateSamplerState(&ShadowMapDesc(), &shadowMap)); - DXCall(device->CreateSamplerState(&ShadowMapPCFDesc(), &shadowMapPCF)); - DXCall(device->CreateSamplerState(&ReversedShadowMapDesc(), &reversedShadowMap)); - DXCall(device->CreateSamplerState(&ReversedShadowMapPCFDesc(), &reversedShadowMapPCF)); -} - -D3D11_SAMPLER_DESC SamplerStates::LinearDesc() -{ - D3D11_SAMPLER_DESC sampDesc; - - sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; - sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; - sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; - sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; - sampDesc.MipLODBias = 0.0f; - sampDesc.MaxAnisotropy = 1; - sampDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; - sampDesc.BorderColor[0] = sampDesc.BorderColor[1] = sampDesc.BorderColor[2] = sampDesc.BorderColor[3] = 0; - sampDesc.MinLOD = 0; - sampDesc.MaxLOD = D3D11_FLOAT32_MAX; - - return sampDesc; -} - -D3D11_SAMPLER_DESC SamplerStates::LinearClampDesc() -{ - D3D11_SAMPLER_DESC sampDesc; - - sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; - sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; - sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; - sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; - sampDesc.MipLODBias = 0.0f; - sampDesc.MaxAnisotropy = 1; - sampDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; - sampDesc.BorderColor[0] = sampDesc.BorderColor[1] = sampDesc.BorderColor[2] = sampDesc.BorderColor[3] = 0; - sampDesc.MinLOD = 0; - sampDesc.MaxLOD = D3D11_FLOAT32_MAX; - - return sampDesc; -} - -D3D11_SAMPLER_DESC SamplerStates::LinearBorderDesc() -{ - D3D11_SAMPLER_DESC sampDesc; - - sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; - sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_BORDER; - sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_BORDER; - sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_BORDER; - sampDesc.MipLODBias = 0.0f; - sampDesc.MaxAnisotropy = 1; - sampDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; - sampDesc.BorderColor[0] = sampDesc.BorderColor[1] = sampDesc.BorderColor[2] = sampDesc.BorderColor[3] = 0; - sampDesc.MinLOD = 0; - sampDesc.MaxLOD = D3D11_FLOAT32_MAX; - - return sampDesc; -} - -D3D11_SAMPLER_DESC SamplerStates::PointDesc() -{ - D3D11_SAMPLER_DESC sampDesc; - - sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; - sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; - sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; - sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; - sampDesc.MipLODBias = 0.0f; - sampDesc.MaxAnisotropy = 1; - sampDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; - sampDesc.BorderColor[0] = sampDesc.BorderColor[1] = sampDesc.BorderColor[2] = sampDesc.BorderColor[3] = 0; - sampDesc.MinLOD = 0; - sampDesc.MaxLOD = D3D11_FLOAT32_MAX; - - return sampDesc; -} - -D3D11_SAMPLER_DESC SamplerStates::AnisotropicDesc() -{ - D3D11_SAMPLER_DESC sampDesc; - - sampDesc.Filter = D3D11_FILTER_ANISOTROPIC; - sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; - sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; - sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; - sampDesc.MipLODBias = 0.0f; - sampDesc.MaxAnisotropy = 16; - sampDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; - sampDesc.BorderColor[0] = sampDesc.BorderColor[1] = sampDesc.BorderColor[2] = sampDesc.BorderColor[3] = 0; - sampDesc.MinLOD = 0; - sampDesc.MaxLOD = D3D11_FLOAT32_MAX; - - return sampDesc; -} - -D3D11_SAMPLER_DESC SamplerStates::ShadowMapDesc() -{ - D3D11_SAMPLER_DESC sampDesc; - - sampDesc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_MIP_POINT; - sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; - sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; - sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; - sampDesc.MipLODBias = 0.0f; - sampDesc.MaxAnisotropy = 1; - sampDesc.ComparisonFunc = D3D11_COMPARISON_LESS_EQUAL; - sampDesc.BorderColor[0] = sampDesc.BorderColor[1] = sampDesc.BorderColor[2] = sampDesc.BorderColor[3] = 0; - sampDesc.MinLOD = 0; - sampDesc.MaxLOD = D3D11_FLOAT32_MAX; - - return sampDesc; -} - -D3D11_SAMPLER_DESC SamplerStates::ShadowMapPCFDesc() -{ - D3D11_SAMPLER_DESC sampDesc; - - sampDesc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR; - sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; - sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; - sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; - sampDesc.MipLODBias = 0.0f; - sampDesc.MaxAnisotropy = 1; - sampDesc.ComparisonFunc = D3D11_COMPARISON_LESS_EQUAL; - sampDesc.BorderColor[0] = sampDesc.BorderColor[1] = sampDesc.BorderColor[2] = sampDesc.BorderColor[3] = 0; - sampDesc.MinLOD = 0; - sampDesc.MaxLOD = D3D11_FLOAT32_MAX; - - return sampDesc; -} - -D3D11_SAMPLER_DESC SamplerStates::ReversedShadowMapDesc() -{ - D3D11_SAMPLER_DESC sampDesc; - - sampDesc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_MIP_POINT; - sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; - sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; - sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; - sampDesc.MipLODBias = 0.0f; - sampDesc.MaxAnisotropy = 1; - sampDesc.ComparisonFunc = D3D11_COMPARISON_GREATER_EQUAL; - sampDesc.BorderColor[0] = sampDesc.BorderColor[1] = sampDesc.BorderColor[2] = sampDesc.BorderColor[3] = 0; - sampDesc.MinLOD = 0; - sampDesc.MaxLOD = D3D11_FLOAT32_MAX; - - return sampDesc; -} - -D3D11_SAMPLER_DESC SamplerStates::ReversedShadowMapPCFDesc() -{ - D3D11_SAMPLER_DESC sampDesc; - - sampDesc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR; - sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; - sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; - sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; - sampDesc.MipLODBias = 0.0f; - sampDesc.MaxAnisotropy = 1; - sampDesc.ComparisonFunc = D3D11_COMPARISON_GREATER_EQUAL; - sampDesc.BorderColor[0] = sampDesc.BorderColor[1] = sampDesc.BorderColor[2] = sampDesc.BorderColor[3] = 0; - sampDesc.MinLOD = 0; - sampDesc.MaxLOD = D3D11_FLOAT32_MAX; - - return sampDesc; -} - +//================================================================================================= +// +// MJP's DX11 Sample Framework +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +#include "PCH.h" + +#include "DeviceStates.h" +#include "..\\Utility.h" + +namespace SampleFramework11 +{ + +void BlendStates::Initialize(ID3D11Device* device) +{ + DXCall(device->CreateBlendState(&BlendDisabledDesc(), &blendDisabled)); + DXCall(device->CreateBlendState(&AdditiveBlendDesc(), &additiveBlend)); + DXCall(device->CreateBlendState(&AlphaBlendDesc(), &alphaBlend)); + DXCall(device->CreateBlendState(&PreMultipliedAlphaBlendDesc(), &pmAlphaBlend)); + DXCall(device->CreateBlendState(&ColorWriteDisabledDesc(), &noColor)); + DXCall(device->CreateBlendState(&AlphaToCoverageDesc(), &alphaToCoverage)); + DXCall(device->CreateBlendState(&OpacityBlendDesc(), &opacityBlend)); +} + +D3D11_BLEND_DESC BlendStates::BlendDisabledDesc() +{ + D3D11_BLEND_DESC blendDesc; + blendDesc.AlphaToCoverageEnable = false; + blendDesc.IndependentBlendEnable = false; + for(UINT i = 0; i < 8; ++i) + { + blendDesc.RenderTarget[i].BlendEnable = false; + blendDesc.RenderTarget[i].BlendOp = D3D11_BLEND_OP_ADD; + blendDesc.RenderTarget[i].BlendOpAlpha = D3D11_BLEND_OP_ADD; + blendDesc.RenderTarget[i].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; + blendDesc.RenderTarget[i].DestBlendAlpha = D3D11_BLEND_ONE; + blendDesc.RenderTarget[i].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + blendDesc.RenderTarget[i].SrcBlend = D3D11_BLEND_SRC_ALPHA; + blendDesc.RenderTarget[i].SrcBlendAlpha = D3D11_BLEND_ONE; + } + + return blendDesc; +} + +D3D11_BLEND_DESC BlendStates::AdditiveBlendDesc() +{ + D3D11_BLEND_DESC blendDesc; + blendDesc.AlphaToCoverageEnable = false; + blendDesc.IndependentBlendEnable = false; + for (uint32 i = 0; i < 8; ++i) + { + blendDesc.RenderTarget[i].BlendEnable = true; + blendDesc.RenderTarget[i].BlendOp = D3D11_BLEND_OP_ADD; + blendDesc.RenderTarget[i].BlendOpAlpha = D3D11_BLEND_OP_ADD; + blendDesc.RenderTarget[i].DestBlend = D3D11_BLEND_ONE; + blendDesc.RenderTarget[i].DestBlendAlpha = D3D11_BLEND_ONE; + blendDesc.RenderTarget[i].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + blendDesc.RenderTarget[i].SrcBlend = D3D11_BLEND_ONE; + blendDesc.RenderTarget[i].SrcBlendAlpha = D3D11_BLEND_ONE; + } + + return blendDesc; +} + +D3D11_BLEND_DESC BlendStates::AlphaBlendDesc() +{ + D3D11_BLEND_DESC blendDesc; + blendDesc.AlphaToCoverageEnable = false; + blendDesc.IndependentBlendEnable = true; + for (uint32 i = 0; i < 8; ++i) + { + blendDesc.RenderTarget[i].BlendEnable = true; + blendDesc.RenderTarget[i].BlendOp = D3D11_BLEND_OP_ADD; + blendDesc.RenderTarget[i].BlendOpAlpha = D3D11_BLEND_OP_ADD; + blendDesc.RenderTarget[i].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; + blendDesc.RenderTarget[i].DestBlendAlpha = D3D11_BLEND_ONE; + blendDesc.RenderTarget[i].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + blendDesc.RenderTarget[i].SrcBlend = D3D11_BLEND_SRC_ALPHA; + blendDesc.RenderTarget[i].SrcBlendAlpha = D3D11_BLEND_ONE; + } + + blendDesc.RenderTarget[0].BlendEnable = true; + + return blendDesc; +} + +D3D11_BLEND_DESC BlendStates::PreMultipliedAlphaBlendDesc() +{ + D3D11_BLEND_DESC blendDesc; + blendDesc.AlphaToCoverageEnable = false; + blendDesc.IndependentBlendEnable = false; + for (uint32 i = 0; i < 8; ++i) + { + blendDesc.RenderTarget[i].BlendEnable = false; + blendDesc.RenderTarget[i].BlendOp = D3D11_BLEND_OP_ADD; + blendDesc.RenderTarget[i].BlendOpAlpha = D3D11_BLEND_OP_ADD; + blendDesc.RenderTarget[i].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; + blendDesc.RenderTarget[i].DestBlendAlpha = D3D11_BLEND_ONE; + blendDesc.RenderTarget[i].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + blendDesc.RenderTarget[i].SrcBlend = D3D11_BLEND_ONE; + blendDesc.RenderTarget[i].SrcBlendAlpha = D3D11_BLEND_ONE; + } + + return blendDesc; +} + +D3D11_BLEND_DESC BlendStates::ColorWriteDisabledDesc() +{ + D3D11_BLEND_DESC blendDesc; + blendDesc.AlphaToCoverageEnable = false; + blendDesc.IndependentBlendEnable = false; + for (uint32 i = 0; i < 8; ++i) + { + blendDesc.RenderTarget[i].BlendEnable = false; + blendDesc.RenderTarget[i].BlendOp = D3D11_BLEND_OP_ADD; + blendDesc.RenderTarget[i].BlendOpAlpha = D3D11_BLEND_OP_ADD; + blendDesc.RenderTarget[i].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; + blendDesc.RenderTarget[i].DestBlendAlpha = D3D11_BLEND_ONE; + blendDesc.RenderTarget[i].RenderTargetWriteMask = 0; + blendDesc.RenderTarget[i].SrcBlend = D3D11_BLEND_SRC_ALPHA; + blendDesc.RenderTarget[i].SrcBlendAlpha = D3D11_BLEND_ONE; + } + + return blendDesc; +} + +D3D11_BLEND_DESC BlendStates::AlphaToCoverageDesc() +{ + D3D11_BLEND_DESC blendDesc; + blendDesc.AlphaToCoverageEnable = true; + blendDesc.IndependentBlendEnable = false; + for (uint32 i = 0; i < 8; ++i) + { + blendDesc.RenderTarget[i].BlendEnable = false; + blendDesc.RenderTarget[i].BlendOp = D3D11_BLEND_OP_ADD; + blendDesc.RenderTarget[i].BlendOpAlpha = D3D11_BLEND_OP_ADD; + blendDesc.RenderTarget[i].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; + blendDesc.RenderTarget[i].DestBlendAlpha = D3D11_BLEND_ONE; + blendDesc.RenderTarget[i].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + blendDesc.RenderTarget[i].SrcBlend = D3D11_BLEND_SRC_ALPHA; + blendDesc.RenderTarget[i].SrcBlendAlpha = D3D11_BLEND_ONE; + } + + return blendDesc; +} + +D3D11_BLEND_DESC BlendStates::OpacityBlendDesc() +{ + D3D11_BLEND_DESC blendDesc; + blendDesc.AlphaToCoverageEnable = false; + blendDesc.IndependentBlendEnable = false; + for (uint32 i = 0; i < 8; ++i) + { + blendDesc.RenderTarget[i].BlendEnable = true; + blendDesc.RenderTarget[i].BlendOp = D3D11_BLEND_OP_ADD; + blendDesc.RenderTarget[i].BlendOpAlpha = D3D11_BLEND_OP_ADD; + blendDesc.RenderTarget[i].DestBlend = D3D11_BLEND_INV_SRC1_COLOR; + blendDesc.RenderTarget[i].DestBlendAlpha = D3D11_BLEND_ONE; + blendDesc.RenderTarget[i].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + blendDesc.RenderTarget[i].SrcBlend = D3D11_BLEND_ONE; + blendDesc.RenderTarget[i].SrcBlendAlpha = D3D11_BLEND_ONE; + } + + return blendDesc; +} + +void RasterizerStates::Initialize(ID3D11Device* device) +{ + DXCall(device->CreateRasterizerState(&NoCullDesc(), &noCull)); + DXCall(device->CreateRasterizerState(&FrontFaceCullDesc(), &cullFrontFaces)); + DXCall(device->CreateRasterizerState(&FrontFaceCullScissorDesc(), &cullFrontFacesScissor)); + DXCall(device->CreateRasterizerState(&BackFaceCullDesc(), &cullBackFaces)); + DXCall(device->CreateRasterizerState(&BackFaceCullScissorDesc(), &cullBackFacesScissor)); + DXCall(device->CreateRasterizerState(&BackFaceCullNoZClipDesc(), &cullBackFacesNoZClip)); + DXCall(device->CreateRasterizerState(&NoCullNoMSDesc(), &noCullNoMS)); + DXCall(device->CreateRasterizerState(&NoCullScissorDesc(), &noCullScissor)); + DXCall(device->CreateRasterizerState(&WireframeDesc(), &wireframe)); + + ID3D11Device3* device3 = nullptr; + device->QueryInterface(IID_PPV_ARGS(&device3)); + DXCall(device3->CreateRasterizerState2(&NoCullConservativeDesc(), &noCullConservative)); + device3->Release(); + device3 = nullptr; +} + +D3D11_RASTERIZER_DESC RasterizerStates::NoCullDesc() +{ + D3D11_RASTERIZER_DESC rastDesc; + + rastDesc.AntialiasedLineEnable = false; + rastDesc.CullMode = D3D11_CULL_NONE; + rastDesc.DepthBias = 0; + rastDesc.DepthBiasClamp = 0.0f; + rastDesc.DepthClipEnable = true; + rastDesc.FillMode = D3D11_FILL_SOLID; + rastDesc.FrontCounterClockwise = false; + rastDesc.MultisampleEnable = true; + rastDesc.ScissorEnable = false; + rastDesc.SlopeScaledDepthBias = 0; + + return rastDesc; +} + +D3D11_RASTERIZER_DESC RasterizerStates::FrontFaceCullDesc() +{ + D3D11_RASTERIZER_DESC rastDesc; + + rastDesc.AntialiasedLineEnable = false; + rastDesc.CullMode = D3D11_CULL_FRONT; + rastDesc.DepthBias = 0; + rastDesc.DepthBiasClamp = 0.0f; + rastDesc.DepthClipEnable = true; + rastDesc.FillMode = D3D11_FILL_SOLID; + rastDesc.FrontCounterClockwise = false; + rastDesc.MultisampleEnable = true; + rastDesc.ScissorEnable = false; + rastDesc.SlopeScaledDepthBias = 0; + + return rastDesc; +} + +D3D11_RASTERIZER_DESC RasterizerStates::FrontFaceCullScissorDesc() +{ + D3D11_RASTERIZER_DESC rastDesc; + + rastDesc.AntialiasedLineEnable = false; + rastDesc.CullMode = D3D11_CULL_FRONT; + rastDesc.DepthBias = 0; + rastDesc.DepthBiasClamp = 0.0f; + rastDesc.DepthClipEnable = true; + rastDesc.FillMode = D3D11_FILL_SOLID; + rastDesc.FrontCounterClockwise = true; + rastDesc.MultisampleEnable = true; + rastDesc.ScissorEnable = true; + rastDesc.SlopeScaledDepthBias = 0; + + return rastDesc; +} + +D3D11_RASTERIZER_DESC RasterizerStates::BackFaceCullDesc() +{ + D3D11_RASTERIZER_DESC rastDesc; + + rastDesc.AntialiasedLineEnable = false; + rastDesc.CullMode = D3D11_CULL_BACK; + rastDesc.DepthBias = 0; + rastDesc.DepthBiasClamp = 0.0f; + rastDesc.DepthClipEnable = true; + rastDesc.FillMode = D3D11_FILL_SOLID; + rastDesc.FrontCounterClockwise = false; + rastDesc.MultisampleEnable = true; + rastDesc.ScissorEnable = false; + rastDesc.SlopeScaledDepthBias = 0; + + return rastDesc; +} + +D3D11_RASTERIZER_DESC RasterizerStates::BackFaceCullScissorDesc() +{ + D3D11_RASTERIZER_DESC rastDesc; + + rastDesc.AntialiasedLineEnable = false; + rastDesc.CullMode = D3D11_CULL_BACK; + rastDesc.DepthBias = 0; + rastDesc.DepthBiasClamp = 0.0f; + rastDesc.DepthClipEnable = true; + rastDesc.FillMode = D3D11_FILL_SOLID; + rastDesc.FrontCounterClockwise = false; + rastDesc.MultisampleEnable = true; + rastDesc.ScissorEnable = true; + rastDesc.SlopeScaledDepthBias = 0; + + return rastDesc; +} + +D3D11_RASTERIZER_DESC RasterizerStates::BackFaceCullNoZClipDesc() +{ + D3D11_RASTERIZER_DESC rastDesc; + + rastDesc.AntialiasedLineEnable = false; + rastDesc.CullMode = D3D11_CULL_BACK; + rastDesc.DepthBias = 0; + rastDesc.DepthBiasClamp = 0.0f; + rastDesc.DepthClipEnable = false; + rastDesc.FillMode = D3D11_FILL_SOLID; + rastDesc.FrontCounterClockwise = false; + rastDesc.MultisampleEnable = true; + rastDesc.ScissorEnable = false; + rastDesc.SlopeScaledDepthBias = 0; + + return rastDesc; +} + +D3D11_RASTERIZER_DESC RasterizerStates::NoCullNoMSDesc() +{ + D3D11_RASTERIZER_DESC rastDesc; + + rastDesc.AntialiasedLineEnable = false; + rastDesc.CullMode = D3D11_CULL_NONE; + rastDesc.DepthBias = 0; + rastDesc.DepthBiasClamp = 0.0f; + rastDesc.DepthClipEnable = true; + rastDesc.FillMode = D3D11_FILL_SOLID; + rastDesc.FrontCounterClockwise = false; + rastDesc.MultisampleEnable = false; + rastDesc.ScissorEnable = false; + rastDesc.SlopeScaledDepthBias = 0; + + return rastDesc; +} + +D3D11_RASTERIZER_DESC RasterizerStates::NoCullScissorDesc() +{ + D3D11_RASTERIZER_DESC rastDesc; + + rastDesc.AntialiasedLineEnable = false; + rastDesc.CullMode = D3D11_CULL_NONE; + rastDesc.DepthBias = 0; + rastDesc.DepthBiasClamp = 0.0f; + rastDesc.DepthClipEnable = true; + rastDesc.FillMode = D3D11_FILL_SOLID; + rastDesc.FrontCounterClockwise = false; + rastDesc.MultisampleEnable = true; + rastDesc.ScissorEnable = true; + rastDesc.SlopeScaledDepthBias = 0; + + return rastDesc; +} + +D3D11_RASTERIZER_DESC RasterizerStates::WireframeDesc() +{ + D3D11_RASTERIZER_DESC rastDesc; + + rastDesc.AntialiasedLineEnable = false; + rastDesc.CullMode = D3D11_CULL_NONE; + rastDesc.DepthBias = 0; + rastDesc.DepthBiasClamp = 0.0f; + rastDesc.DepthClipEnable = true; + rastDesc.FillMode = D3D11_FILL_WIREFRAME; + rastDesc.FrontCounterClockwise = false; + rastDesc.MultisampleEnable = true; + rastDesc.ScissorEnable = false; + rastDesc.SlopeScaledDepthBias = 0; + + return rastDesc; +} + +D3D11_RASTERIZER_DESC2 RasterizerStates::NoCullConservativeDesc() +{ + D3D11_RASTERIZER_DESC2 rastDesc = { }; + rastDesc.AntialiasedLineEnable = false; + rastDesc.CullMode = D3D11_CULL_NONE; + rastDesc.DepthBias = 0; + rastDesc.DepthBiasClamp = 0.0f; + rastDesc.DepthClipEnable = true; + rastDesc.FillMode = D3D11_FILL_SOLID; + rastDesc.FrontCounterClockwise = false; + rastDesc.MultisampleEnable = true; + rastDesc.ScissorEnable = false; + rastDesc.SlopeScaledDepthBias = 0; + rastDesc.ConservativeRaster = D3D11_CONSERVATIVE_RASTERIZATION_MODE_ON; + + return rastDesc; +} + +void DepthStencilStates::Initialize(ID3D11Device* device) +{ + DXCall(device->CreateDepthStencilState(&DepthDisabledDesc(), &depthDisabled)); + DXCall(device->CreateDepthStencilState(&DepthEnabledDesc(), &depthEnabled)); + DXCall(device->CreateDepthStencilState(&ReverseDepthEnabledDesc(), &revDepthEnabled)); + DXCall(device->CreateDepthStencilState(&DepthWriteEnabledDesc(), &depthWriteEnabled)); + DXCall(device->CreateDepthStencilState(&ReverseDepthWriteEnabledDesc(), &revDepthWriteEnabled)); + DXCall(device->CreateDepthStencilState(&DepthStencilWriteEnabledDesc(), &depthStencilWriteEnabled)); + DXCall(device->CreateDepthStencilState(&StencilEnabledDesc(), &stencilEnabled)); + DXCall(device->CreateDepthStencilState(&StencilEnabledDesc(), &stencilEnabled)); +} + +D3D11_DEPTH_STENCIL_DESC DepthStencilStates::DepthDisabledDesc() +{ + D3D11_DEPTH_STENCIL_DESC dsDesc; + dsDesc.DepthEnable = false; + dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; + dsDesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL; + dsDesc.StencilEnable = false; + dsDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; + dsDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; + dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + dsDesc.BackFace = dsDesc.FrontFace; + + return dsDesc; +} + +D3D11_DEPTH_STENCIL_DESC DepthStencilStates::DepthEnabledDesc() +{ + D3D11_DEPTH_STENCIL_DESC dsDesc; + dsDesc.DepthEnable = true; + dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; + dsDesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL; + dsDesc.StencilEnable = false; + dsDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; + dsDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; + dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + dsDesc.BackFace = dsDesc.FrontFace; + + return dsDesc; +} + +D3D11_DEPTH_STENCIL_DESC DepthStencilStates::ReverseDepthEnabledDesc() +{ + D3D11_DEPTH_STENCIL_DESC dsDesc; + dsDesc.DepthEnable = true; + dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; + dsDesc.DepthFunc = D3D11_COMPARISON_GREATER_EQUAL; + dsDesc.StencilEnable = false; + dsDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; + dsDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; + dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + dsDesc.BackFace = dsDesc.FrontFace; + + return dsDesc; +} + +D3D11_DEPTH_STENCIL_DESC DepthStencilStates::DepthWriteEnabledDesc() +{ + D3D11_DEPTH_STENCIL_DESC dsDesc; + dsDesc.DepthEnable = true; + dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + dsDesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL; + dsDesc.StencilEnable = false; + dsDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; + dsDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; + dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + dsDesc.BackFace = dsDesc.FrontFace; + + return dsDesc; +} + +D3D11_DEPTH_STENCIL_DESC DepthStencilStates::ReverseDepthWriteEnabledDesc() +{ + D3D11_DEPTH_STENCIL_DESC dsDesc; + dsDesc.DepthEnable = true; + dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + dsDesc.DepthFunc = D3D11_COMPARISON_GREATER_EQUAL; + dsDesc.StencilEnable = false; + dsDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; + dsDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; + dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + dsDesc.BackFace = dsDesc.FrontFace; + + return dsDesc; +} + +D3D11_DEPTH_STENCIL_DESC DepthStencilStates::DepthStencilWriteEnabledDesc() +{ + D3D11_DEPTH_STENCIL_DESC dsDesc; + dsDesc.DepthEnable = true; + dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + dsDesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL; + dsDesc.StencilEnable = true; + dsDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; + dsDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; + dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + dsDesc.BackFace = dsDesc.FrontFace; + + return dsDesc; +} + +D3D11_DEPTH_STENCIL_DESC DepthStencilStates::StencilEnabledDesc() +{ + D3D11_DEPTH_STENCIL_DESC dsDesc; + dsDesc.DepthEnable = true; + dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + dsDesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL; + dsDesc.StencilEnable = true; + dsDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; + dsDesc.StencilWriteMask = 0; + dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; + dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_EQUAL; + dsDesc.BackFace = dsDesc.FrontFace; + + return dsDesc; +} + +void SamplerStates::Initialize(ID3D11Device* device) +{ + DXCall(device->CreateSamplerState(&LinearDesc(), &linear)); + DXCall(device->CreateSamplerState(&LinearClampDesc(), &linearClamp)); + DXCall(device->CreateSamplerState(&LinearBorderDesc(), &linearBorder)); + DXCall(device->CreateSamplerState(&PointDesc(), &point)); + DXCall(device->CreateSamplerState(&AnisotropicDesc(), &anisotropic)); + DXCall(device->CreateSamplerState(&ShadowMapDesc(), &shadowMap)); + DXCall(device->CreateSamplerState(&ShadowMapPCFDesc(), &shadowMapPCF)); + DXCall(device->CreateSamplerState(&ReversedShadowMapDesc(), &reversedShadowMap)); + DXCall(device->CreateSamplerState(&ReversedShadowMapPCFDesc(), &reversedShadowMapPCF)); +} + +D3D11_SAMPLER_DESC SamplerStates::LinearDesc() +{ + D3D11_SAMPLER_DESC sampDesc; + + sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; + sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; + sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; + sampDesc.MipLODBias = 0.0f; + sampDesc.MaxAnisotropy = 1; + sampDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; + sampDesc.BorderColor[0] = sampDesc.BorderColor[1] = sampDesc.BorderColor[2] = sampDesc.BorderColor[3] = 0; + sampDesc.MinLOD = 0; + sampDesc.MaxLOD = D3D11_FLOAT32_MAX; + + return sampDesc; +} + +D3D11_SAMPLER_DESC SamplerStates::LinearClampDesc() +{ + D3D11_SAMPLER_DESC sampDesc; + + sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; + sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + sampDesc.MipLODBias = 0.0f; + sampDesc.MaxAnisotropy = 1; + sampDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; + sampDesc.BorderColor[0] = sampDesc.BorderColor[1] = sampDesc.BorderColor[2] = sampDesc.BorderColor[3] = 0; + sampDesc.MinLOD = 0; + sampDesc.MaxLOD = D3D11_FLOAT32_MAX; + + return sampDesc; +} + +D3D11_SAMPLER_DESC SamplerStates::LinearBorderDesc() +{ + D3D11_SAMPLER_DESC sampDesc; + + sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_BORDER; + sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_BORDER; + sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_BORDER; + sampDesc.MipLODBias = 0.0f; + sampDesc.MaxAnisotropy = 1; + sampDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; + sampDesc.BorderColor[0] = sampDesc.BorderColor[1] = sampDesc.BorderColor[2] = sampDesc.BorderColor[3] = 0; + sampDesc.MinLOD = 0; + sampDesc.MaxLOD = D3D11_FLOAT32_MAX; + + return sampDesc; +} + +D3D11_SAMPLER_DESC SamplerStates::PointDesc() +{ + D3D11_SAMPLER_DESC sampDesc; + + sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; + sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; + sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + sampDesc.MipLODBias = 0.0f; + sampDesc.MaxAnisotropy = 1; + sampDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; + sampDesc.BorderColor[0] = sampDesc.BorderColor[1] = sampDesc.BorderColor[2] = sampDesc.BorderColor[3] = 0; + sampDesc.MinLOD = 0; + sampDesc.MaxLOD = D3D11_FLOAT32_MAX; + + return sampDesc; +} + +D3D11_SAMPLER_DESC SamplerStates::AnisotropicDesc() +{ + D3D11_SAMPLER_DESC sampDesc; + + sampDesc.Filter = D3D11_FILTER_ANISOTROPIC; + sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; + sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; + sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; + sampDesc.MipLODBias = 0.0f; + sampDesc.MaxAnisotropy = 16; + sampDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; + sampDesc.BorderColor[0] = sampDesc.BorderColor[1] = sampDesc.BorderColor[2] = sampDesc.BorderColor[3] = 0; + sampDesc.MinLOD = 0; + sampDesc.MaxLOD = D3D11_FLOAT32_MAX; + + return sampDesc; +} + +D3D11_SAMPLER_DESC SamplerStates::ShadowMapDesc() +{ + D3D11_SAMPLER_DESC sampDesc; + + sampDesc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_MIP_POINT; + sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; + sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + sampDesc.MipLODBias = 0.0f; + sampDesc.MaxAnisotropy = 1; + sampDesc.ComparisonFunc = D3D11_COMPARISON_LESS_EQUAL; + sampDesc.BorderColor[0] = sampDesc.BorderColor[1] = sampDesc.BorderColor[2] = sampDesc.BorderColor[3] = 0; + sampDesc.MinLOD = 0; + sampDesc.MaxLOD = D3D11_FLOAT32_MAX; + + return sampDesc; +} + +D3D11_SAMPLER_DESC SamplerStates::ShadowMapPCFDesc() +{ + D3D11_SAMPLER_DESC sampDesc; + + sampDesc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR; + sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; + sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + sampDesc.MipLODBias = 0.0f; + sampDesc.MaxAnisotropy = 1; + sampDesc.ComparisonFunc = D3D11_COMPARISON_LESS_EQUAL; + sampDesc.BorderColor[0] = sampDesc.BorderColor[1] = sampDesc.BorderColor[2] = sampDesc.BorderColor[3] = 0; + sampDesc.MinLOD = 0; + sampDesc.MaxLOD = D3D11_FLOAT32_MAX; + + return sampDesc; +} + +D3D11_SAMPLER_DESC SamplerStates::ReversedShadowMapDesc() +{ + D3D11_SAMPLER_DESC sampDesc; + + sampDesc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_MIP_POINT; + sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; + sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + sampDesc.MipLODBias = 0.0f; + sampDesc.MaxAnisotropy = 1; + sampDesc.ComparisonFunc = D3D11_COMPARISON_GREATER_EQUAL; + sampDesc.BorderColor[0] = sampDesc.BorderColor[1] = sampDesc.BorderColor[2] = sampDesc.BorderColor[3] = 0; + sampDesc.MinLOD = 0; + sampDesc.MaxLOD = D3D11_FLOAT32_MAX; + + return sampDesc; +} + +D3D11_SAMPLER_DESC SamplerStates::ReversedShadowMapPCFDesc() +{ + D3D11_SAMPLER_DESC sampDesc; + + sampDesc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR; + sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; + sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + sampDesc.MipLODBias = 0.0f; + sampDesc.MaxAnisotropy = 1; + sampDesc.ComparisonFunc = D3D11_COMPARISON_GREATER_EQUAL; + sampDesc.BorderColor[0] = sampDesc.BorderColor[1] = sampDesc.BorderColor[2] = sampDesc.BorderColor[3] = 0; + sampDesc.MinLOD = 0; + sampDesc.MaxLOD = D3D11_FLOAT32_MAX; + + return sampDesc; +} + } \ No newline at end of file diff --git a/SampleFramework11/v1.02/Graphics/DeviceStates.h b/SampleFramework11/v1.02/Graphics/DeviceStates.h index 2cc5076..b36eeed 100644 --- a/SampleFramework11/v1.02/Graphics/DeviceStates.h +++ b/SampleFramework11/v1.02/Graphics/DeviceStates.h @@ -1,164 +1,167 @@ -//================================================================================================= -// -// MJP's DX11 Sample Framework -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -#pragma once - -#include "..\\PCH.h" - -#include "..\\InterfacePointers.h" - -namespace SampleFramework11 -{ - -class BlendStates -{ - -protected: - - ID3D11BlendStatePtr blendDisabled; - ID3D11BlendStatePtr additiveBlend; - ID3D11BlendStatePtr alphaBlend; - ID3D11BlendStatePtr pmAlphaBlend; - ID3D11BlendStatePtr noColor; - ID3D11BlendStatePtr alphaToCoverage; - ID3D11BlendStatePtr opacityBlend; - -public: - - void Initialize(ID3D11Device* device); - - ID3D11BlendState* BlendDisabled () { return blendDisabled; }; - ID3D11BlendState* AdditiveBlend () { return additiveBlend; }; - ID3D11BlendState* AlphaBlend () { return alphaBlend; }; - ID3D11BlendState* PreMultipliedAlphaBlend () { return pmAlphaBlend; }; - ID3D11BlendState* ColorWriteDisabled () { return noColor; }; - ID3D11BlendState* AlphaToCoverage () { return alphaToCoverage; }; - ID3D11BlendState* OpacityBlend() { return opacityBlend; }; - - static D3D11_BLEND_DESC BlendDisabledDesc(); - static D3D11_BLEND_DESC AdditiveBlendDesc(); - static D3D11_BLEND_DESC AlphaBlendDesc(); - static D3D11_BLEND_DESC PreMultipliedAlphaBlendDesc(); - static D3D11_BLEND_DESC ColorWriteDisabledDesc(); - static D3D11_BLEND_DESC AlphaToCoverageDesc(); - static D3D11_BLEND_DESC OpacityBlendDesc(); -}; - - -class RasterizerStates -{ - -protected: - - ID3D11RasterizerStatePtr noCull; - ID3D11RasterizerStatePtr cullBackFaces; - ID3D11RasterizerStatePtr cullBackFacesScissor; - ID3D11RasterizerStatePtr cullBackFacesNoZClip; - ID3D11RasterizerStatePtr cullFrontFaces; - ID3D11RasterizerStatePtr cullFrontFacesScissor; - ID3D11RasterizerStatePtr noCullNoMS; - ID3D11RasterizerStatePtr noCullScissor; - ID3D11RasterizerStatePtr wireframe; - -public: - - void Initialize(ID3D11Device* device); - - ID3D11RasterizerState* NoCull() { return noCull; }; - ID3D11RasterizerState* BackFaceCull() { return cullBackFaces; }; - ID3D11RasterizerState* BackFaceCullScissor() { return cullBackFacesScissor; }; - ID3D11RasterizerState* BackFaceCullNoZClip() { return cullBackFacesNoZClip; }; - ID3D11RasterizerState* FrontFaceCull() { return cullFrontFaces; }; - ID3D11RasterizerState* FrontFaceCullScissor() { return cullFrontFacesScissor; }; - ID3D11RasterizerState* NoCullNoMS() { return noCullNoMS; }; - ID3D11RasterizerState* NoCullScissor() { return noCullScissor; }; - ID3D11RasterizerState* Wireframe() { return wireframe; }; - - static D3D11_RASTERIZER_DESC NoCullDesc(); - static D3D11_RASTERIZER_DESC FrontFaceCullDesc(); - static D3D11_RASTERIZER_DESC FrontFaceCullScissorDesc(); - static D3D11_RASTERIZER_DESC BackFaceCullDesc(); - static D3D11_RASTERIZER_DESC BackFaceCullScissorDesc(); - static D3D11_RASTERIZER_DESC BackFaceCullNoZClipDesc(); - static D3D11_RASTERIZER_DESC NoCullNoMSDesc(); - static D3D11_RASTERIZER_DESC NoCullScissorDesc(); - static D3D11_RASTERIZER_DESC WireframeDesc(); -}; - - -class DepthStencilStates -{ - ID3D11DepthStencilStatePtr depthDisabled; - ID3D11DepthStencilStatePtr depthEnabled; - ID3D11DepthStencilStatePtr revDepthEnabled; - ID3D11DepthStencilStatePtr depthWriteEnabled; - ID3D11DepthStencilStatePtr revDepthWriteEnabled; - ID3D11DepthStencilStatePtr depthStencilWriteEnabled; - ID3D11DepthStencilStatePtr stencilEnabled; - -public: - - void Initialize(ID3D11Device* device); - - ID3D11DepthStencilState* DepthDisabled() { return depthDisabled; }; - ID3D11DepthStencilState* DepthEnabled() { return depthEnabled; }; - ID3D11DepthStencilState* ReverseDepthEnabled() { return revDepthEnabled; }; - ID3D11DepthStencilState* DepthWriteEnabled() { return depthWriteEnabled; }; - ID3D11DepthStencilState* ReverseDepthWriteEnabled() { return revDepthWriteEnabled; }; - ID3D11DepthStencilState* DepthStencilWriteEnabled() { return depthStencilWriteEnabled; }; - ID3D11DepthStencilState* StencilTestEnabled() { return depthStencilWriteEnabled; }; - - static D3D11_DEPTH_STENCIL_DESC DepthDisabledDesc(); - static D3D11_DEPTH_STENCIL_DESC DepthEnabledDesc(); - static D3D11_DEPTH_STENCIL_DESC ReverseDepthEnabledDesc(); - static D3D11_DEPTH_STENCIL_DESC DepthWriteEnabledDesc(); - static D3D11_DEPTH_STENCIL_DESC ReverseDepthWriteEnabledDesc(); - static D3D11_DEPTH_STENCIL_DESC DepthStencilWriteEnabledDesc(); - static D3D11_DEPTH_STENCIL_DESC StencilEnabledDesc(); -}; - - -class SamplerStates -{ - - ID3D11SamplerStatePtr linear; - ID3D11SamplerStatePtr linearClamp; - ID3D11SamplerStatePtr linearBorder; - ID3D11SamplerStatePtr point; - ID3D11SamplerStatePtr anisotropic; - ID3D11SamplerStatePtr shadowMap; - ID3D11SamplerStatePtr shadowMapPCF; - ID3D11SamplerStatePtr reversedShadowMap; - ID3D11SamplerStatePtr reversedShadowMapPCF; -public: - - void Initialize(ID3D11Device* device); - - ID3D11SamplerState* Linear() { return linear; }; - ID3D11SamplerState* LinearClamp() { return linearClamp; }; - ID3D11SamplerState* LinearBorder() { return linearBorder; }; - ID3D11SamplerState* Point() { return point; }; - ID3D11SamplerState* Anisotropic() { return anisotropic; }; - ID3D11SamplerState* ShadowMap() { return shadowMap; }; - ID3D11SamplerState* ShadowMapPCF() { return shadowMapPCF; }; - ID3D11SamplerState* ReversedShadowMap() { return reversedShadowMap; }; - ID3D11SamplerState* ReversedShadowMapPCF() { return reversedShadowMapPCF; }; - - static D3D11_SAMPLER_DESC LinearDesc(); - static D3D11_SAMPLER_DESC LinearClampDesc(); - static D3D11_SAMPLER_DESC LinearBorderDesc(); - static D3D11_SAMPLER_DESC PointDesc(); - static D3D11_SAMPLER_DESC AnisotropicDesc(); - static D3D11_SAMPLER_DESC ShadowMapDesc(); - static D3D11_SAMPLER_DESC ShadowMapPCFDesc(); - static D3D11_SAMPLER_DESC ReversedShadowMapDesc(); - static D3D11_SAMPLER_DESC ReversedShadowMapPCFDesc(); -}; - -} +//================================================================================================= +// +// MJP's DX11 Sample Framework +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +#pragma once + +#include "..\\PCH.h" + +#include "..\\InterfacePointers.h" + +namespace SampleFramework11 +{ + +class BlendStates +{ + +protected: + + ID3D11BlendStatePtr blendDisabled; + ID3D11BlendStatePtr additiveBlend; + ID3D11BlendStatePtr alphaBlend; + ID3D11BlendStatePtr pmAlphaBlend; + ID3D11BlendStatePtr noColor; + ID3D11BlendStatePtr alphaToCoverage; + ID3D11BlendStatePtr opacityBlend; + +public: + + void Initialize(ID3D11Device* device); + + ID3D11BlendState* BlendDisabled () { return blendDisabled; }; + ID3D11BlendState* AdditiveBlend () { return additiveBlend; }; + ID3D11BlendState* AlphaBlend () { return alphaBlend; }; + ID3D11BlendState* PreMultipliedAlphaBlend () { return pmAlphaBlend; }; + ID3D11BlendState* ColorWriteDisabled () { return noColor; }; + ID3D11BlendState* AlphaToCoverage () { return alphaToCoverage; }; + ID3D11BlendState* OpacityBlend() { return opacityBlend; }; + + static D3D11_BLEND_DESC BlendDisabledDesc(); + static D3D11_BLEND_DESC AdditiveBlendDesc(); + static D3D11_BLEND_DESC AlphaBlendDesc(); + static D3D11_BLEND_DESC PreMultipliedAlphaBlendDesc(); + static D3D11_BLEND_DESC ColorWriteDisabledDesc(); + static D3D11_BLEND_DESC AlphaToCoverageDesc(); + static D3D11_BLEND_DESC OpacityBlendDesc(); +}; + + +class RasterizerStates +{ + +protected: + + ID3D11RasterizerStatePtr noCull; + ID3D11RasterizerStatePtr cullBackFaces; + ID3D11RasterizerStatePtr cullBackFacesScissor; + ID3D11RasterizerStatePtr cullBackFacesNoZClip; + ID3D11RasterizerStatePtr cullFrontFaces; + ID3D11RasterizerStatePtr cullFrontFacesScissor; + ID3D11RasterizerStatePtr noCullNoMS; + ID3D11RasterizerStatePtr noCullScissor; + ID3D11RasterizerStatePtr wireframe; + ID3D11RasterizerState2Ptr noCullConservative; + +public: + + void Initialize(ID3D11Device* device); + + ID3D11RasterizerState* NoCull() { return noCull; }; + ID3D11RasterizerState* BackFaceCull() { return cullBackFaces; }; + ID3D11RasterizerState* BackFaceCullScissor() { return cullBackFacesScissor; }; + ID3D11RasterizerState* BackFaceCullNoZClip() { return cullBackFacesNoZClip; }; + ID3D11RasterizerState* FrontFaceCull() { return cullFrontFaces; }; + ID3D11RasterizerState* FrontFaceCullScissor() { return cullFrontFacesScissor; }; + ID3D11RasterizerState* NoCullNoMS() { return noCullNoMS; }; + ID3D11RasterizerState* NoCullScissor() { return noCullScissor; }; + ID3D11RasterizerState* Wireframe() { return wireframe; }; + ID3D11RasterizerState2* NoCullConservative() { return noCullConservative; }; + + static D3D11_RASTERIZER_DESC NoCullDesc(); + static D3D11_RASTERIZER_DESC FrontFaceCullDesc(); + static D3D11_RASTERIZER_DESC FrontFaceCullScissorDesc(); + static D3D11_RASTERIZER_DESC BackFaceCullDesc(); + static D3D11_RASTERIZER_DESC BackFaceCullScissorDesc(); + static D3D11_RASTERIZER_DESC BackFaceCullNoZClipDesc(); + static D3D11_RASTERIZER_DESC NoCullNoMSDesc(); + static D3D11_RASTERIZER_DESC NoCullScissorDesc(); + static D3D11_RASTERIZER_DESC WireframeDesc(); + static D3D11_RASTERIZER_DESC2 NoCullConservativeDesc(); +}; + + +class DepthStencilStates +{ + ID3D11DepthStencilStatePtr depthDisabled; + ID3D11DepthStencilStatePtr depthEnabled; + ID3D11DepthStencilStatePtr revDepthEnabled; + ID3D11DepthStencilStatePtr depthWriteEnabled; + ID3D11DepthStencilStatePtr revDepthWriteEnabled; + ID3D11DepthStencilStatePtr depthStencilWriteEnabled; + ID3D11DepthStencilStatePtr stencilEnabled; + +public: + + void Initialize(ID3D11Device* device); + + ID3D11DepthStencilState* DepthDisabled() { return depthDisabled; }; + ID3D11DepthStencilState* DepthEnabled() { return depthEnabled; }; + ID3D11DepthStencilState* ReverseDepthEnabled() { return revDepthEnabled; }; + ID3D11DepthStencilState* DepthWriteEnabled() { return depthWriteEnabled; }; + ID3D11DepthStencilState* ReverseDepthWriteEnabled() { return revDepthWriteEnabled; }; + ID3D11DepthStencilState* DepthStencilWriteEnabled() { return depthStencilWriteEnabled; }; + ID3D11DepthStencilState* StencilTestEnabled() { return depthStencilWriteEnabled; }; + + static D3D11_DEPTH_STENCIL_DESC DepthDisabledDesc(); + static D3D11_DEPTH_STENCIL_DESC DepthEnabledDesc(); + static D3D11_DEPTH_STENCIL_DESC ReverseDepthEnabledDesc(); + static D3D11_DEPTH_STENCIL_DESC DepthWriteEnabledDesc(); + static D3D11_DEPTH_STENCIL_DESC ReverseDepthWriteEnabledDesc(); + static D3D11_DEPTH_STENCIL_DESC DepthStencilWriteEnabledDesc(); + static D3D11_DEPTH_STENCIL_DESC StencilEnabledDesc(); +}; + + +class SamplerStates +{ + + ID3D11SamplerStatePtr linear; + ID3D11SamplerStatePtr linearClamp; + ID3D11SamplerStatePtr linearBorder; + ID3D11SamplerStatePtr point; + ID3D11SamplerStatePtr anisotropic; + ID3D11SamplerStatePtr shadowMap; + ID3D11SamplerStatePtr shadowMapPCF; + ID3D11SamplerStatePtr reversedShadowMap; + ID3D11SamplerStatePtr reversedShadowMapPCF; +public: + + void Initialize(ID3D11Device* device); + + ID3D11SamplerState* Linear() { return linear; }; + ID3D11SamplerState* LinearClamp() { return linearClamp; }; + ID3D11SamplerState* LinearBorder() { return linearBorder; }; + ID3D11SamplerState* Point() { return point; }; + ID3D11SamplerState* Anisotropic() { return anisotropic; }; + ID3D11SamplerState* ShadowMap() { return shadowMap; }; + ID3D11SamplerState* ShadowMapPCF() { return shadowMapPCF; }; + ID3D11SamplerState* ReversedShadowMap() { return reversedShadowMap; }; + ID3D11SamplerState* ReversedShadowMapPCF() { return reversedShadowMapPCF; }; + + static D3D11_SAMPLER_DESC LinearDesc(); + static D3D11_SAMPLER_DESC LinearClampDesc(); + static D3D11_SAMPLER_DESC LinearBorderDesc(); + static D3D11_SAMPLER_DESC PointDesc(); + static D3D11_SAMPLER_DESC AnisotropicDesc(); + static D3D11_SAMPLER_DESC ShadowMapDesc(); + static D3D11_SAMPLER_DESC ShadowMapPCFDesc(); + static D3D11_SAMPLER_DESC ReversedShadowMapDesc(); + static D3D11_SAMPLER_DESC ReversedShadowMapPCFDesc(); +}; + +} diff --git a/SampleFramework11/v1.02/Graphics/GraphicsTypes.cpp b/SampleFramework11/v1.02/Graphics/GraphicsTypes.cpp index 88c6f47..27a041e 100644 --- a/SampleFramework11/v1.02/Graphics/GraphicsTypes.cpp +++ b/SampleFramework11/v1.02/Graphics/GraphicsTypes.cpp @@ -1,635 +1,696 @@ -//================================================================================================= -// -// MJP's DX11 Sample Framework -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -#include "PCH.h" - -#include "GraphicsTypes.h" -#include "..\\Exceptions.h" -#include "..\\Utility.h" -#include "..\\Serialization.h" -#include "..\\FileIO.h" - -namespace SampleFramework11 -{ - -// == RenderTarget2D ============================================================================== - -RenderTarget2D::RenderTarget2D() : Width(0), - Height(0), - Format(DXGI_FORMAT_UNKNOWN), - NumMipLevels(0), - MultiSamples(0), - MSQuality(0), - AutoGenMipMaps(false), - UAView(nullptr), - ArraySize(1) -{ - -} - -void RenderTarget2D::Initialize(ID3D11Device* device, - uint32 width, - uint32 height, - DXGI_FORMAT format, - uint32 numMipLevels, - uint32 multiSamples, - uint32 msQuality, - bool32 autoGenMipMaps, - bool32 createUAV, - uint32 arraySize, - bool32 cubeMap) -{ - D3D11_TEXTURE2D_DESC desc; - desc.Width = width; - desc.Height = height; - desc.ArraySize = arraySize; - desc.BindFlags = D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_RENDER_TARGET; - if(createUAV) - desc.BindFlags |= D3D11_BIND_UNORDERED_ACCESS; - - desc.CPUAccessFlags = 0; - desc.Format = format; - desc.MipLevels = numMipLevels; - desc.MiscFlags = (autoGenMipMaps && numMipLevels != 1) ? D3D11_RESOURCE_MISC_GENERATE_MIPS : 0; - desc.SampleDesc.Count = multiSamples; - desc.SampleDesc.Quality = msQuality; - desc.Usage = D3D11_USAGE_DEFAULT; - - if(cubeMap) - { - Assert_(arraySize == 6); - desc.MiscFlags |= D3D11_RESOURCE_MISC_TEXTURECUBE; - } - - DXCall(device->CreateTexture2D(&desc, nullptr, &Texture)); - - RTVArraySlices.clear(); - RTVArraySlices.reserve(arraySize); - for(uint32 i = 0; i < arraySize; ++i) - { - ID3D11RenderTargetViewPtr rtView; - D3D11_RENDER_TARGET_VIEW_DESC rtDesc; - rtDesc.Format = format; - - if(arraySize == 1) - { - if(multiSamples > 1) - { - rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS; - } - else - { - rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; - rtDesc.Texture2D.MipSlice = 0; - } - } - else - { - if(multiSamples > 1) - { - rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY; - rtDesc.Texture2DMSArray.ArraySize = 1; - rtDesc.Texture2DMSArray.FirstArraySlice = i; - } - else - { - rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; - rtDesc.Texture2DArray.ArraySize = 1; - rtDesc.Texture2DArray.FirstArraySlice = i; - rtDesc.Texture2DArray.MipSlice = 0; - } - } - DXCall(device->CreateRenderTargetView(Texture, &rtDesc, &rtView)); - - RTVArraySlices.push_back(rtView); - } - - RTView = RTVArraySlices[0]; - - DXCall(device->CreateShaderResourceView(Texture, nullptr, &SRView)); - - SRVArraySlices.clear(); - for(uint32 i = 0; i < arraySize; ++i) - { - ID3D11ShaderResourceViewPtr srView; - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = format; - - if(arraySize == 1) - { - if(multiSamples > 1) - { - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMS; - } - else - { - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; - srvDesc.Texture2D.MipLevels = -1; - srvDesc.Texture2D.MostDetailedMip = 0; - } - } - else - { - if(multiSamples > 1) - { - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY; - srvDesc.Texture2DMSArray.ArraySize = 1; - srvDesc.Texture2DMSArray.FirstArraySlice = i; - } - else - { - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; - srvDesc.Texture2DArray.ArraySize = 1; - srvDesc.Texture2DArray.FirstArraySlice = i; - srvDesc.Texture2DArray.MipLevels = -1; - srvDesc.Texture2DArray.MostDetailedMip = 0; - } - } - - DXCall(device->CreateShaderResourceView(Texture, &srvDesc, &srView)); - SRVArraySlices.push_back(srView); - } - - Width = width; - Height = height; - NumMipLevels = numMipLevels; - MultiSamples = multiSamples; - Format = format; - AutoGenMipMaps = autoGenMipMaps; - ArraySize = arraySize; - CubeMap = cubeMap; - - if(createUAV) - DXCall(device->CreateUnorderedAccessView(Texture, nullptr, &UAView)); -}; - -// == DepthStencilBuffer ========================================================================== - -DepthStencilBuffer::DepthStencilBuffer() : Width(0), - Height(0), - MultiSamples(0), - MSQuality(0), - Format(DXGI_FORMAT_UNKNOWN), - ArraySize(1), - CubeMap(false) -{ - -} - -void DepthStencilBuffer::Initialize(ID3D11Device* device, - uint32 width, - uint32 height, - DXGI_FORMAT format, - bool32 useAsShaderResource, - uint32 multiSamples, - uint32 msQuality, - uint32 arraySize, - bool32 cubeMap) -{ - Width = width; - Height = height; - MultiSamples = multiSamples; - Format = format; - ArraySize = arraySize; - CubeMap = cubeMap; - - uint32 bindFlags = D3D11_BIND_DEPTH_STENCIL; - if(useAsShaderResource) - bindFlags |= D3D11_BIND_SHADER_RESOURCE; - - DXGI_FORMAT dsTexFormat; - if (!useAsShaderResource) - dsTexFormat = format; - else if (format == DXGI_FORMAT_D16_UNORM) - dsTexFormat = DXGI_FORMAT_R16_TYPELESS; - else if(format == DXGI_FORMAT_D24_UNORM_S8_UINT) - dsTexFormat = DXGI_FORMAT_R24G8_TYPELESS; - else - dsTexFormat = DXGI_FORMAT_R32_TYPELESS; - - D3D11_TEXTURE2D_DESC desc; - desc.Width = width; - desc.Height = height; - desc.ArraySize = arraySize; - desc.BindFlags = bindFlags; - desc.CPUAccessFlags = 0; - desc.Format = dsTexFormat; - desc.MipLevels = 1; - desc.MiscFlags = 0; - if(cubeMap) - { - Assert_(arraySize == 6); - Assert_(multiSamples == 1); - desc.MiscFlags |= D3D11_RESOURCE_MISC_TEXTURECUBE; - } - desc.SampleDesc.Count = multiSamples; - desc.SampleDesc.Quality = msQuality; - desc.Usage = D3D11_USAGE_DEFAULT; - DXCall(device->CreateTexture2D(&desc, nullptr, &Texture)); - - ArraySlices.clear(); - for(uint32 i = 0; i < arraySize; ++i) - { - D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; - ID3D11DepthStencilViewPtr dsView; - dsvDesc.Format = format; - - if(arraySize == 1) - { - dsvDesc.ViewDimension = multiSamples > 1 ? D3D11_DSV_DIMENSION_TEXTURE2DMS : D3D11_DSV_DIMENSION_TEXTURE2D; - dsvDesc.Texture2D.MipSlice = 0; - } - else - { - if(multiSamples > 1) - { - dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY; - dsvDesc.Texture2DMSArray.ArraySize = 1; - dsvDesc.Texture2DMSArray.FirstArraySlice = i; - } - else - { - dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY; - dsvDesc.Texture2DArray.ArraySize = 1; - dsvDesc.Texture2DArray.FirstArraySlice = i; - dsvDesc.Texture2DArray.MipSlice = 0; - } - } - - dsvDesc.Flags = 0; - DXCall(device->CreateDepthStencilView(Texture, &dsvDesc, &dsView)); - ArraySlices.push_back(dsView); - - if (i == 0) - { - // Also create a read-only DSV - dsvDesc.Flags = D3D11_DSV_READ_ONLY_DEPTH; - if (format == DXGI_FORMAT_D24_UNORM_S8_UINT || format == DXGI_FORMAT_D32_FLOAT_S8X24_UINT) - dsvDesc.Flags |= D3D11_DSV_READ_ONLY_STENCIL; - DXCall(device->CreateDepthStencilView(Texture, &dsvDesc, &ReadOnlyDSView)); - dsvDesc.Flags = 0; - } - } - - DSView = ArraySlices[0]; - - if(useAsShaderResource) - { - DXGI_FORMAT dsSRVFormat; - if (format == DXGI_FORMAT_D16_UNORM) - dsSRVFormat = DXGI_FORMAT_R16_UNORM; - else if(format == DXGI_FORMAT_D24_UNORM_S8_UINT) - dsSRVFormat = DXGI_FORMAT_R24_UNORM_X8_TYPELESS ; - else - dsSRVFormat = DXGI_FORMAT_R32_FLOAT; - - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = dsSRVFormat; - - if(arraySize == 1) - { - srvDesc.ViewDimension = multiSamples > 1 ? D3D11_SRV_DIMENSION_TEXTURE2DMS : D3D11_SRV_DIMENSION_TEXTURE2D; - srvDesc.Texture2D.MipLevels = 1; - srvDesc.Texture2D.MostDetailedMip = 0; - } - else if(cubeMap) - { - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; - srvDesc.TextureCube.MipLevels = 1; - srvDesc.TextureCube.MostDetailedMip = 0; - } - else - { - srvDesc.ViewDimension = multiSamples > 1 ? D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY : D3D11_SRV_DIMENSION_TEXTURE2DARRAY; - srvDesc.Texture2DArray.ArraySize = arraySize; - srvDesc.Texture2DArray.FirstArraySlice = 0; - srvDesc.Texture2DArray.MipLevels = 1; - srvDesc.Texture2DArray.MostDetailedMip = 0; - } - - DXCall(device->CreateShaderResourceView(Texture, &srvDesc, &SRView)); - } - else - SRView = nullptr; -} - -// == RWBuffer ==================================================================================== - -RWBuffer::RWBuffer() : Size(0), Stride(0), NumElements(0), Format(DXGI_FORMAT_UNKNOWN), RawBuffer(false) -{ - -} - -void RWBuffer::Initialize(ID3D11Device* device, DXGI_FORMAT format, uint32 stride, uint32 numElements, - bool32 rawBuffer, bool vertexBuffer, bool indexBuffer, bool indirectArgs, - const void* initData) -{ - if(rawBuffer) - { - stride = 4; - Format = DXGI_FORMAT_R32_TYPELESS; - } - - Format = format; - Size = stride * numElements; - Stride = stride; - NumElements = numElements; - RawBuffer = rawBuffer; - - D3D11_BUFFER_DESC bufferDesc; - bufferDesc.ByteWidth = stride * numElements; - bufferDesc.Usage = D3D11_USAGE_DEFAULT; - bufferDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS; - bufferDesc.CPUAccessFlags = 0; - bufferDesc.MiscFlags = rawBuffer ? D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS : 0; - bufferDesc.StructureByteStride = 0; - - Assert_(vertexBuffer == false || indexBuffer == false); - - if(vertexBuffer) - bufferDesc.BindFlags |= D3D11_BIND_VERTEX_BUFFER; - - if(indexBuffer) - { - bufferDesc.BindFlags |= D3D11_BIND_INDEX_BUFFER; - Assert_(Format == DXGI_FORMAT_R32_TYPELESS || - Format == DXGI_FORMAT_R32_UINT || - Format == DXGI_FORMAT_R16_UINT); - } - - if(indirectArgs) - bufferDesc.MiscFlags |= D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS; - - D3D11_SUBRESOURCE_DATA srData; - srData.pSysMem = initData; - srData.SysMemPitch = 0; - srData.SysMemSlicePitch = 0; - - DXCall(device->CreateBuffer(&bufferDesc, initData ? &srData : nullptr, &Buffer)); - - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = Format; - - if(rawBuffer) - { - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFEREX; - srvDesc.BufferEx.FirstElement = 0; - srvDesc.BufferEx.NumElements = numElements; - srvDesc.BufferEx.Flags = D3D11_BUFFEREX_SRV_FLAG_RAW; - } - else - { - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; - srvDesc.Buffer.ElementOffset = 0; - srvDesc.Buffer.NumElements = numElements; - } - - DXCall(device->CreateShaderResourceView(Buffer, &srvDesc, &SRView)); - - D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc; - uavDesc.Format = format; - uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; - uavDesc.Buffer.FirstElement = 0; - uavDesc.Buffer.NumElements = numElements; - uavDesc.Buffer.Flags = rawBuffer ? D3D11_BUFFER_UAV_FLAG_RAW : 0; - - DXCall(device->CreateUnorderedAccessView(Buffer, &uavDesc, &UAView)); -} - -// == StructuredBuffer ============================================================================ - -StructuredBuffer::StructuredBuffer() : Size(0), Stride(0), NumElements(0) -{ -} - -void StructuredBuffer::Initialize(ID3D11Device* device, uint32 stride, uint32 numElements, bool32 useAsUAV, - bool32 appendConsume, bool32 hiddenCounter, const void* initData) -{ - Size = stride * numElements; - Stride = stride; - NumElements = numElements; - - Assert_(appendConsume == false || hiddenCounter == false); - - if(appendConsume || hiddenCounter) - useAsUAV = true; - - D3D11_BUFFER_DESC bufferDesc; - bufferDesc.ByteWidth = stride * numElements; - bufferDesc.Usage = useAsUAV ? D3D11_USAGE_DEFAULT : D3D11_USAGE_IMMUTABLE; - bufferDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - bufferDesc.BindFlags |= useAsUAV ? D3D11_BIND_UNORDERED_ACCESS : 0; - bufferDesc.CPUAccessFlags = 0; - bufferDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; - bufferDesc.StructureByteStride = stride; - - D3D11_SUBRESOURCE_DATA subresourceData; - subresourceData.pSysMem = initData; - subresourceData.SysMemPitch = 0; - subresourceData.SysMemSlicePitch = 0; - - DXCall(device->CreateBuffer(&bufferDesc, initData != nullptr ? &subresourceData : nullptr, &Buffer)); - - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = DXGI_FORMAT_UNKNOWN; - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; - srvDesc.Buffer.FirstElement = 0; - srvDesc.Buffer.NumElements = numElements; - DXCall(device->CreateShaderResourceView(Buffer, &srvDesc, &SRView)); - - if(useAsUAV) - { - D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc; - uavDesc.Format = DXGI_FORMAT_UNKNOWN; - uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; - uavDesc.Buffer.FirstElement = 0; - uavDesc.Buffer.Flags = 0; - uavDesc.Buffer.Flags |= appendConsume ? D3D11_BUFFER_UAV_FLAG_APPEND : 0; - uavDesc.Buffer.Flags |= hiddenCounter ? D3D11_BUFFER_UAV_FLAG_COUNTER : 0; - uavDesc.Buffer.NumElements = numElements; - DXCall(device->CreateUnorderedAccessView(Buffer, &uavDesc, &UAView)); - } -} - -void StructuredBuffer::WriteToFile(const wchar* path, ID3D11Device* device, ID3D11DeviceContext* context) -{ - Assert_(Buffer != nullptr); - - // Get the buffer info - D3D11_BUFFER_DESC desc; - Buffer->GetDesc(&desc); - - uint32 useAsUAV = (desc.BindFlags & D3D11_BIND_UNORDERED_ACCESS) ? 1 : 0; - - uint32 appendConsume = 0; - uint32 hiddenCounter = 0; - if(useAsUAV) - { - D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc; - UAView->GetDesc(&uavDesc); - appendConsume = (uavDesc.Format & D3D11_BUFFER_UAV_FLAG_APPEND) ? 1 : 0; - hiddenCounter =(uavDesc.Format & D3D11_BUFFER_UAV_FLAG_COUNTER) ? 1 : 0; - } - - // If the exists, delete it - if(FileExists(path)) - Win32Call(DeleteFile(path)); - - // Create the file - HANDLE fileHandle = CreateFile(path, GENERIC_WRITE, 0, nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr); - if(fileHandle == INVALID_HANDLE_VALUE) - Win32Call(false); - - // Write the buffer info - DWORD bytesWritten = 0; - Win32Call(WriteFile(fileHandle, &Size, 4, &bytesWritten, nullptr)); - Win32Call(WriteFile(fileHandle, &Stride, 4, &bytesWritten, nullptr)); - Win32Call(WriteFile(fileHandle, &NumElements, 4, &bytesWritten, nullptr)); - Win32Call(WriteFile(fileHandle, &useAsUAV, 4, &bytesWritten, nullptr)); - Win32Call(WriteFile(fileHandle, &hiddenCounter, 4, &bytesWritten, nullptr)); - Win32Call(WriteFile(fileHandle, &appendConsume, 4, &bytesWritten, nullptr)); - - // Get the buffer data - StagingBuffer stagingBuffer; - stagingBuffer.Initialize(device, Size); - context->CopyResource(stagingBuffer.Buffer, Buffer); - const void* bufferData= stagingBuffer.Map(context); - - // Write the data to the file - Win32Call(WriteFile(fileHandle, bufferData, Size, &bytesWritten, nullptr)); - - // Un-map the staging buffer - stagingBuffer.Unmap(context); - - // Close the file - Win32Call(CloseHandle(fileHandle)); -} - -void StructuredBuffer::ReadFromFile(const wchar* path, ID3D11Device* device) -{ - // Open the file - HANDLE fileHandle = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); - if(fileHandle == INVALID_HANDLE_VALUE) - Win32Call(false); - - // Read the buffer info - bool32 useAsUAV, hiddenCounter, appendConsume; - DWORD bytesRead = 0; - Win32Call(ReadFile(fileHandle, &Size, 4, &bytesRead, nullptr)); - Win32Call(ReadFile(fileHandle, &Stride, 4, &bytesRead, nullptr)); - Win32Call(ReadFile(fileHandle, &NumElements, 4, &bytesRead, nullptr)); - Win32Call(ReadFile(fileHandle, &useAsUAV, 4, &bytesRead, nullptr)); - Win32Call(ReadFile(fileHandle, &hiddenCounter, 4, &bytesRead, nullptr)); - Win32Call(ReadFile(fileHandle, &appendConsume, 4, &bytesRead, nullptr)); - - // Read the buffer data - UINT8* bufferData = new UINT8[Size]; - Win32Call(ReadFile(fileHandle, bufferData, Size, &bytesRead, nullptr)); - - // Close the file - Win32Call(CloseHandle(fileHandle)); - - // Init - Initialize(device, Stride, NumElements, useAsUAV, appendConsume, hiddenCounter, bufferData); - - // Clean up - delete [] bufferData; -} - -// == StagingBuffer =============================================================================== - -StagingBuffer::StagingBuffer() : Size(0) -{ -} - -void StagingBuffer::Initialize(ID3D11Device* device, uint32 size) -{ - Size = size; - - D3D11_BUFFER_DESC bufferDesc; - bufferDesc.ByteWidth = Size; - bufferDesc.Usage = D3D11_USAGE_STAGING; - bufferDesc.BindFlags = 0; - bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - bufferDesc.MiscFlags = 0; - bufferDesc.StructureByteStride = 0; - DXCall(device->CreateBuffer(&bufferDesc, nullptr, &Buffer)); -} - -void* StagingBuffer::Map(ID3D11DeviceContext* context) -{ - D3D11_MAPPED_SUBRESOURCE mapped; - DXCall(context->Map(Buffer, 0, D3D11_MAP_READ, 0, &mapped)); - - return mapped.pData; -} - -void StagingBuffer::Unmap(ID3D11DeviceContext* context) -{ - context->Unmap(Buffer, 0); -} - -// == StagingTexture2D ============================================================================ - -StagingTexture2D::StagingTexture2D() : Width(0), - Height(0), - Format(DXGI_FORMAT_UNKNOWN), - NumMipLevels(0), - MultiSamples(0), - MSQuality(0), - ArraySize(1) -{ -} - -void StagingTexture2D::Initialize(ID3D11Device* device, - uint32 width, - uint32 height, - DXGI_FORMAT format, - uint32 numMipLevels, - uint32 multiSamples, - uint32 msQuality, - uint32 arraySize) -{ - D3D11_TEXTURE2D_DESC desc; - desc.Width = width; - desc.Height = height; - desc.ArraySize = arraySize; - desc.BindFlags = 0; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - desc.Format = format; - desc.MipLevels = numMipLevels; - desc.MiscFlags = 0; - desc.SampleDesc.Count = multiSamples; - desc.SampleDesc.Quality = msQuality; - desc.Usage = D3D11_USAGE_STAGING; - DXCall(device->CreateTexture2D(&desc, nullptr, &Texture)); - - - Width = width; - Height = height; - NumMipLevels = numMipLevels; - MultiSamples = multiSamples; - Format = format; - ArraySize = arraySize; -}; - -void* StagingTexture2D::Map(ID3D11DeviceContext* context, uint32 subResourceIndex, uint32& pitch) -{ - D3D11_MAPPED_SUBRESOURCE mapped; - DXCall(context->Map(Texture, subResourceIndex, D3D11_MAP_READ, 0, &mapped)); - pitch = mapped.RowPitch; - return mapped.pData; -} - -void StagingTexture2D::Unmap(ID3D11DeviceContext* context, uint32 subResourceIndex) -{ - context->Unmap(Texture, subResourceIndex); -} - +//================================================================================================= +// +// MJP's DX11 Sample Framework +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +#include "PCH.h" + +#include "GraphicsTypes.h" +#include "..\\Exceptions.h" +#include "..\\Utility.h" +#include "..\\Serialization.h" +#include "..\\FileIO.h" + +namespace SampleFramework11 +{ + +// == RenderTarget2D ============================================================================== + +RenderTarget2D::RenderTarget2D() : Width(0), + Height(0), + Format(DXGI_FORMAT_UNKNOWN), + NumMipLevels(0), + MultiSamples(0), + MSQuality(0), + AutoGenMipMaps(false), + UAView(nullptr), + ArraySize(0) +{ + +} + +void RenderTarget2D::Initialize(ID3D11Device* device, + uint32 width, + uint32 height, + DXGI_FORMAT format, + uint32 numMipLevels, + uint32 multiSamples, + uint32 msQuality, + bool32 autoGenMipMaps, + bool32 createUAV, + uint32 arraySize, + bool32 cubeMap) +{ + D3D11_TEXTURE2D_DESC desc; + desc.Width = width; + desc.Height = height; + desc.ArraySize = arraySize; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_RENDER_TARGET; + if(createUAV) + desc.BindFlags |= D3D11_BIND_UNORDERED_ACCESS; + + desc.CPUAccessFlags = 0; + desc.Format = format; + desc.MipLevels = numMipLevels; + desc.MiscFlags = (autoGenMipMaps && numMipLevels != 1) ? D3D11_RESOURCE_MISC_GENERATE_MIPS : 0; + desc.SampleDesc.Count = multiSamples; + desc.SampleDesc.Quality = msQuality; + desc.Usage = D3D11_USAGE_DEFAULT; + + if(cubeMap) + { + Assert_(arraySize % 6 == 0); + desc.MiscFlags |= D3D11_RESOURCE_MISC_TEXTURECUBE; + } + + DXCall(device->CreateTexture2D(&desc, nullptr, &Texture)); + + RTVArraySlices.clear(); + RTVArraySlices.reserve(arraySize); + for(uint32 i = 0; i < arraySize; ++i) + { + ID3D11RenderTargetViewPtr rtView; + D3D11_RENDER_TARGET_VIEW_DESC rtDesc; + rtDesc.Format = format; + + if(arraySize == 1) + { + if(multiSamples > 1) + { + rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS; + } + else + { + rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rtDesc.Texture2D.MipSlice = 0; + } + } + else + { + if(multiSamples > 1) + { + rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY; + rtDesc.Texture2DMSArray.ArraySize = 1; + rtDesc.Texture2DMSArray.FirstArraySlice = i; + } + else + { + rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtDesc.Texture2DArray.ArraySize = 1; + rtDesc.Texture2DArray.FirstArraySlice = i; + rtDesc.Texture2DArray.MipSlice = 0; + } + } + DXCall(device->CreateRenderTargetView(Texture, &rtDesc, &rtView)); + + RTVArraySlices.push_back(rtView); + } + + RTView = RTVArraySlices[0]; + + DXCall(device->CreateShaderResourceView(Texture, nullptr, &SRView)); + + uint32 numSRVSlices = cubeMap ? arraySize / 6 : arraySize; + SRVArraySlices.clear(); + SRVArraySlices.reserve(numSRVSlices); + for(uint32 i = 0; i < numSRVSlices; ++i) + { + ID3D11ShaderResourceViewPtr srView; + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = format; + + if(multiSamples > 1) + { + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY; + srvDesc.Texture2DMSArray.ArraySize = 1; + srvDesc.Texture2DMSArray.FirstArraySlice = i; + } + else if(cubeMap) + { + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBEARRAY; + srvDesc.TextureCubeArray.MostDetailedMip = 0; + srvDesc.TextureCubeArray.MipLevels = -1; + srvDesc.TextureCubeArray.First2DArrayFace = i; + srvDesc.TextureCubeArray.NumCubes = 1; + } + else + { + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + srvDesc.Texture2DArray.ArraySize = 1; + srvDesc.Texture2DArray.FirstArraySlice = i; + srvDesc.Texture2DArray.MipLevels = -1; + srvDesc.Texture2DArray.MostDetailedMip = 0; + } + + DXCall(device->CreateShaderResourceView(Texture, &srvDesc, &srView)); + SRVArraySlices.push_back(srView); + } + + Width = width; + Height = height; + NumMipLevels = numMipLevels; + MultiSamples = multiSamples; + Format = format; + AutoGenMipMaps = autoGenMipMaps; + ArraySize = arraySize; + CubeMap = cubeMap; + + if(createUAV) + DXCall(device->CreateUnorderedAccessView(Texture, nullptr, &UAView)); +}; + +// == RenderTarget3D ============================================================================== + +void RenderTarget3D::Initialize(ID3D11Device* device, + uint32 width, + uint32 height, + uint32 depth, + DXGI_FORMAT format, + uint32 numMipLevels, + bool32 createUAV) +{ + D3D11_TEXTURE3D_DESC desc = { }; + desc.Width = width; + desc.Height = height; + desc.Depth = depth; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + if(createUAV) + desc.BindFlags |= D3D11_BIND_UNORDERED_ACCESS; + + desc.CPUAccessFlags = 0; + desc.Format = format; + desc.MipLevels = numMipLevels; + desc.Usage = D3D11_USAGE_DEFAULT; + + DXCall(device->CreateTexture3D(&desc, nullptr, &Texture)); + + DXCall(device->CreateShaderResourceView(Texture, nullptr, &SRView)); + + if(createUAV) + DXCall(device->CreateUnorderedAccessView(Texture, nullptr, &UAView)); + + Width = width; + Height = height; + Depth = depth; + NumMipLevels = numMipLevels; + Format = format; + + MipSRVs.Init(numMipLevels); + if(createUAV) + MipUAVs.Init(numMipLevels); + + uint32 mipDepth = depth; + for(uint32 mipLevel = 0; mipLevel < numMipLevels; ++mipLevel) + { + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = { }; + srvDesc.Format = format; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D; + srvDesc.Texture3D.MostDetailedMip = mipLevel; + srvDesc.Texture3D.MipLevels = 1; + + DXCall(device->CreateShaderResourceView(Texture, &srvDesc, &MipSRVs[mipLevel])); + + if(createUAV) + { + D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc = { }; + uavDesc.Format = format; + uavDesc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE3D; + uavDesc.Texture3D.MipSlice = mipLevel; + uavDesc.Texture3D.FirstWSlice = 0; + uavDesc.Texture3D.WSize = mipDepth; + + DXCall(device->CreateUnorderedAccessView(Texture, &uavDesc, &MipUAVs[mipLevel])); + } + + mipDepth = mipDepth > 1 ? mipDepth / 2: 1; + } +}; + +// == DepthStencilBuffer ========================================================================== + +DepthStencilBuffer::DepthStencilBuffer() : Width(0), + Height(0), + MultiSamples(0), + MSQuality(0), + Format(DXGI_FORMAT_UNKNOWN), + ArraySize(1), + CubeMap(false) +{ + +} + +void DepthStencilBuffer::Initialize(ID3D11Device* device, + uint32 width, + uint32 height, + DXGI_FORMAT format, + bool32 useAsShaderResource, + uint32 multiSamples, + uint32 msQuality, + uint32 arraySize, + bool32 cubeMap) +{ + Width = width; + Height = height; + MultiSamples = multiSamples; + Format = format; + ArraySize = arraySize; + CubeMap = cubeMap; + + uint32 bindFlags = D3D11_BIND_DEPTH_STENCIL; + if(useAsShaderResource) + bindFlags |= D3D11_BIND_SHADER_RESOURCE; + + DXGI_FORMAT dsTexFormat; + if (!useAsShaderResource) + dsTexFormat = format; + else if (format == DXGI_FORMAT_D16_UNORM) + dsTexFormat = DXGI_FORMAT_R16_TYPELESS; + else if(format == DXGI_FORMAT_D24_UNORM_S8_UINT) + dsTexFormat = DXGI_FORMAT_R24G8_TYPELESS; + else + dsTexFormat = DXGI_FORMAT_R32_TYPELESS; + + D3D11_TEXTURE2D_DESC desc; + desc.Width = width; + desc.Height = height; + desc.ArraySize = arraySize; + desc.BindFlags = bindFlags; + desc.CPUAccessFlags = 0; + desc.Format = dsTexFormat; + desc.MipLevels = 1; + desc.MiscFlags = 0; + if(cubeMap) + { + Assert_(arraySize == 6); + Assert_(multiSamples == 1); + desc.MiscFlags |= D3D11_RESOURCE_MISC_TEXTURECUBE; + } + desc.SampleDesc.Count = multiSamples; + desc.SampleDesc.Quality = msQuality; + desc.Usage = D3D11_USAGE_DEFAULT; + DXCall(device->CreateTexture2D(&desc, nullptr, &Texture)); + + ArraySlices.clear(); + for(uint32 i = 0; i < arraySize; ++i) + { + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + ID3D11DepthStencilViewPtr dsView; + dsvDesc.Format = format; + + if(arraySize == 1) + { + dsvDesc.ViewDimension = multiSamples > 1 ? D3D11_DSV_DIMENSION_TEXTURE2DMS : D3D11_DSV_DIMENSION_TEXTURE2D; + dsvDesc.Texture2D.MipSlice = 0; + } + else + { + if(multiSamples > 1) + { + dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY; + dsvDesc.Texture2DMSArray.ArraySize = 1; + dsvDesc.Texture2DMSArray.FirstArraySlice = i; + } + else + { + dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY; + dsvDesc.Texture2DArray.ArraySize = 1; + dsvDesc.Texture2DArray.FirstArraySlice = i; + dsvDesc.Texture2DArray.MipSlice = 0; + } + } + + dsvDesc.Flags = 0; + DXCall(device->CreateDepthStencilView(Texture, &dsvDesc, &dsView)); + ArraySlices.push_back(dsView); + + if (i == 0) + { + // Also create a read-only DSV + dsvDesc.Flags = D3D11_DSV_READ_ONLY_DEPTH; + if (format == DXGI_FORMAT_D24_UNORM_S8_UINT || format == DXGI_FORMAT_D32_FLOAT_S8X24_UINT) + dsvDesc.Flags |= D3D11_DSV_READ_ONLY_STENCIL; + DXCall(device->CreateDepthStencilView(Texture, &dsvDesc, &ReadOnlyDSView)); + dsvDesc.Flags = 0; + } + } + + DSView = ArraySlices[0]; + + if(useAsShaderResource) + { + DXGI_FORMAT dsSRVFormat; + if (format == DXGI_FORMAT_D16_UNORM) + dsSRVFormat = DXGI_FORMAT_R16_UNORM; + else if(format == DXGI_FORMAT_D24_UNORM_S8_UINT) + dsSRVFormat = DXGI_FORMAT_R24_UNORM_X8_TYPELESS ; + else + dsSRVFormat = DXGI_FORMAT_R32_FLOAT; + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = dsSRVFormat; + + if(arraySize == 1) + { + srvDesc.ViewDimension = multiSamples > 1 ? D3D11_SRV_DIMENSION_TEXTURE2DMS : D3D11_SRV_DIMENSION_TEXTURE2D; + srvDesc.Texture2D.MipLevels = 1; + srvDesc.Texture2D.MostDetailedMip = 0; + } + else if(cubeMap) + { + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE; + srvDesc.TextureCube.MipLevels = 1; + srvDesc.TextureCube.MostDetailedMip = 0; + } + else + { + srvDesc.ViewDimension = multiSamples > 1 ? D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY : D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + srvDesc.Texture2DArray.ArraySize = arraySize; + srvDesc.Texture2DArray.FirstArraySlice = 0; + srvDesc.Texture2DArray.MipLevels = 1; + srvDesc.Texture2DArray.MostDetailedMip = 0; + } + + DXCall(device->CreateShaderResourceView(Texture, &srvDesc, &SRView)); + } + else + SRView = nullptr; +} + +// == RWBuffer ==================================================================================== + +RWBuffer::RWBuffer() : Size(0), Stride(0), NumElements(0), Format(DXGI_FORMAT_UNKNOWN), RawBuffer(false) +{ + +} + +void RWBuffer::Initialize(ID3D11Device* device, DXGI_FORMAT format, uint32 stride, uint32 numElements, + bool32 rawBuffer, bool vertexBuffer, bool indexBuffer, bool indirectArgs, + const void* initData) +{ + if(rawBuffer) + { + stride = 4; + Format = DXGI_FORMAT_R32_TYPELESS; + } + + Format = format; + Size = stride * numElements; + Stride = stride; + NumElements = numElements; + RawBuffer = rawBuffer; + + D3D11_BUFFER_DESC bufferDesc; + bufferDesc.ByteWidth = stride * numElements; + bufferDesc.Usage = D3D11_USAGE_DEFAULT; + bufferDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS; + bufferDesc.CPUAccessFlags = 0; + bufferDesc.MiscFlags = rawBuffer ? D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS : 0; + bufferDesc.StructureByteStride = 0; + + Assert_(vertexBuffer == false || indexBuffer == false); + + if(vertexBuffer) + bufferDesc.BindFlags |= D3D11_BIND_VERTEX_BUFFER; + + if(indexBuffer) + { + bufferDesc.BindFlags |= D3D11_BIND_INDEX_BUFFER; + Assert_(Format == DXGI_FORMAT_R32_TYPELESS || + Format == DXGI_FORMAT_R32_UINT || + Format == DXGI_FORMAT_R16_UINT); + } + + if(indirectArgs) + bufferDesc.MiscFlags |= D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS; + + D3D11_SUBRESOURCE_DATA srData; + srData.pSysMem = initData; + srData.SysMemPitch = 0; + srData.SysMemSlicePitch = 0; + + DXCall(device->CreateBuffer(&bufferDesc, initData ? &srData : nullptr, &Buffer)); + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = Format; + + if(rawBuffer) + { + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFEREX; + srvDesc.BufferEx.FirstElement = 0; + srvDesc.BufferEx.NumElements = numElements; + srvDesc.BufferEx.Flags = D3D11_BUFFEREX_SRV_FLAG_RAW; + } + else + { + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; + srvDesc.Buffer.ElementOffset = 0; + srvDesc.Buffer.NumElements = numElements; + } + + DXCall(device->CreateShaderResourceView(Buffer, &srvDesc, &SRView)); + + D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc; + uavDesc.Format = format; + uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; + uavDesc.Buffer.FirstElement = 0; + uavDesc.Buffer.NumElements = numElements; + uavDesc.Buffer.Flags = rawBuffer ? D3D11_BUFFER_UAV_FLAG_RAW : 0; + + DXCall(device->CreateUnorderedAccessView(Buffer, &uavDesc, &UAView)); +} + +// == StructuredBuffer ============================================================================ + +StructuredBuffer::StructuredBuffer() : Size(0), Stride(0), NumElements(0) +{ +} + +void StructuredBuffer::Initialize(ID3D11Device* device, uint32 stride, uint32 numElements, bool32 useAsUAV, + bool32 appendConsume, bool32 hiddenCounter, const void* initData) +{ + Size = stride * numElements; + Stride = stride; + NumElements = numElements; + + Assert_(appendConsume == false || hiddenCounter == false); + + if(appendConsume || hiddenCounter) + useAsUAV = true; + + D3D11_BUFFER_DESC bufferDesc; + bufferDesc.ByteWidth = stride * numElements; + bufferDesc.Usage = useAsUAV ? D3D11_USAGE_DEFAULT : D3D11_USAGE_IMMUTABLE; + bufferDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + bufferDesc.BindFlags |= useAsUAV ? D3D11_BIND_UNORDERED_ACCESS : 0; + bufferDesc.CPUAccessFlags = 0; + bufferDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; + bufferDesc.StructureByteStride = stride; + + D3D11_SUBRESOURCE_DATA subresourceData; + subresourceData.pSysMem = initData; + subresourceData.SysMemPitch = 0; + subresourceData.SysMemSlicePitch = 0; + + DXCall(device->CreateBuffer(&bufferDesc, initData != nullptr ? &subresourceData : nullptr, &Buffer)); + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = DXGI_FORMAT_UNKNOWN; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; + srvDesc.Buffer.FirstElement = 0; + srvDesc.Buffer.NumElements = numElements; + DXCall(device->CreateShaderResourceView(Buffer, &srvDesc, &SRView)); + + if(useAsUAV) + { + D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc; + uavDesc.Format = DXGI_FORMAT_UNKNOWN; + uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; + uavDesc.Buffer.FirstElement = 0; + uavDesc.Buffer.Flags = 0; + uavDesc.Buffer.Flags |= appendConsume ? D3D11_BUFFER_UAV_FLAG_APPEND : 0; + uavDesc.Buffer.Flags |= hiddenCounter ? D3D11_BUFFER_UAV_FLAG_COUNTER : 0; + uavDesc.Buffer.NumElements = numElements; + DXCall(device->CreateUnorderedAccessView(Buffer, &uavDesc, &UAView)); + } +} + +void StructuredBuffer::WriteToFile(const wchar* path, ID3D11Device* device, ID3D11DeviceContext* context) +{ + Assert_(Buffer != nullptr); + + // Get the buffer info + D3D11_BUFFER_DESC desc; + Buffer->GetDesc(&desc); + + uint32 useAsUAV = (desc.BindFlags & D3D11_BIND_UNORDERED_ACCESS) ? 1 : 0; + + uint32 appendConsume = 0; + uint32 hiddenCounter = 0; + if(useAsUAV) + { + D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc; + UAView->GetDesc(&uavDesc); + appendConsume = (uavDesc.Format & D3D11_BUFFER_UAV_FLAG_APPEND) ? 1 : 0; + hiddenCounter =(uavDesc.Format & D3D11_BUFFER_UAV_FLAG_COUNTER) ? 1 : 0; + } + + // If the exists, delete it + if(FileExists(path)) + Win32Call(DeleteFile(path)); + + // Create the file + HANDLE fileHandle = CreateFile(path, GENERIC_WRITE, 0, nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr); + if(fileHandle == INVALID_HANDLE_VALUE) + Win32Call(false); + + // Write the buffer info + DWORD bytesWritten = 0; + Win32Call(WriteFile(fileHandle, &Size, 4, &bytesWritten, nullptr)); + Win32Call(WriteFile(fileHandle, &Stride, 4, &bytesWritten, nullptr)); + Win32Call(WriteFile(fileHandle, &NumElements, 4, &bytesWritten, nullptr)); + Win32Call(WriteFile(fileHandle, &useAsUAV, 4, &bytesWritten, nullptr)); + Win32Call(WriteFile(fileHandle, &hiddenCounter, 4, &bytesWritten, nullptr)); + Win32Call(WriteFile(fileHandle, &appendConsume, 4, &bytesWritten, nullptr)); + + // Get the buffer data + StagingBuffer stagingBuffer; + stagingBuffer.Initialize(device, Size); + context->CopyResource(stagingBuffer.Buffer, Buffer); + const void* bufferData= stagingBuffer.Map(context); + + // Write the data to the file + Win32Call(WriteFile(fileHandle, bufferData, Size, &bytesWritten, nullptr)); + + // Un-map the staging buffer + stagingBuffer.Unmap(context); + + // Close the file + Win32Call(CloseHandle(fileHandle)); +} + +void StructuredBuffer::ReadFromFile(const wchar* path, ID3D11Device* device) +{ + // Open the file + HANDLE fileHandle = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); + if(fileHandle == INVALID_HANDLE_VALUE) + Win32Call(false); + + // Read the buffer info + bool32 useAsUAV, hiddenCounter, appendConsume; + DWORD bytesRead = 0; + Win32Call(ReadFile(fileHandle, &Size, 4, &bytesRead, nullptr)); + Win32Call(ReadFile(fileHandle, &Stride, 4, &bytesRead, nullptr)); + Win32Call(ReadFile(fileHandle, &NumElements, 4, &bytesRead, nullptr)); + Win32Call(ReadFile(fileHandle, &useAsUAV, 4, &bytesRead, nullptr)); + Win32Call(ReadFile(fileHandle, &hiddenCounter, 4, &bytesRead, nullptr)); + Win32Call(ReadFile(fileHandle, &appendConsume, 4, &bytesRead, nullptr)); + + // Read the buffer data + UINT8* bufferData = new UINT8[Size]; + Win32Call(ReadFile(fileHandle, bufferData, Size, &bytesRead, nullptr)); + + // Close the file + Win32Call(CloseHandle(fileHandle)); + + // Init + Initialize(device, Stride, NumElements, useAsUAV, appendConsume, hiddenCounter, bufferData); + + // Clean up + delete [] bufferData; +} + +// == StagingBuffer =============================================================================== + +StagingBuffer::StagingBuffer() : Size(0) +{ +} + +void StagingBuffer::Initialize(ID3D11Device* device, uint32 size) +{ + Size = size; + + D3D11_BUFFER_DESC bufferDesc; + bufferDesc.ByteWidth = Size; + bufferDesc.Usage = D3D11_USAGE_STAGING; + bufferDesc.BindFlags = 0; + bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + bufferDesc.MiscFlags = 0; + bufferDesc.StructureByteStride = 0; + DXCall(device->CreateBuffer(&bufferDesc, nullptr, &Buffer)); +} + +void* StagingBuffer::Map(ID3D11DeviceContext* context) +{ + D3D11_MAPPED_SUBRESOURCE mapped; + DXCall(context->Map(Buffer, 0, D3D11_MAP_READ, 0, &mapped)); + + return mapped.pData; +} + +void StagingBuffer::Unmap(ID3D11DeviceContext* context) +{ + context->Unmap(Buffer, 0); +} + +// == StagingTexture2D ============================================================================ + +StagingTexture2D::StagingTexture2D() : Width(0), + Height(0), + Format(DXGI_FORMAT_UNKNOWN), + NumMipLevels(0), + MultiSamples(0), + MSQuality(0), + ArraySize(1) +{ +} + +void StagingTexture2D::Initialize(ID3D11Device* device, + uint32 width, + uint32 height, + DXGI_FORMAT format, + uint32 numMipLevels, + uint32 multiSamples, + uint32 msQuality, + uint32 arraySize) +{ + D3D11_TEXTURE2D_DESC desc; + desc.Width = width; + desc.Height = height; + desc.ArraySize = arraySize; + desc.BindFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + desc.Format = format; + desc.MipLevels = numMipLevels; + desc.MiscFlags = 0; + desc.SampleDesc.Count = multiSamples; + desc.SampleDesc.Quality = msQuality; + desc.Usage = D3D11_USAGE_STAGING; + DXCall(device->CreateTexture2D(&desc, nullptr, &Texture)); + + + Width = width; + Height = height; + NumMipLevels = numMipLevels; + MultiSamples = multiSamples; + Format = format; + ArraySize = arraySize; +}; + +void* StagingTexture2D::Map(ID3D11DeviceContext* context, uint32 subResourceIndex, uint32& pitch) +{ + D3D11_MAPPED_SUBRESOURCE mapped; + DXCall(context->Map(Texture, subResourceIndex, D3D11_MAP_READ, 0, &mapped)); + pitch = mapped.RowPitch; + return mapped.pData; +} + +void StagingTexture2D::Unmap(ID3D11DeviceContext* context, uint32 subResourceIndex) +{ + context->Unmap(Texture, subResourceIndex); +} + } \ No newline at end of file diff --git a/SampleFramework11/v1.02/Graphics/GraphicsTypes.h b/SampleFramework11/v1.02/Graphics/GraphicsTypes.h index c39ac06..6917d52 100644 --- a/SampleFramework11/v1.02/Graphics/GraphicsTypes.h +++ b/SampleFramework11/v1.02/Graphics/GraphicsTypes.h @@ -1,307 +1,330 @@ -//================================================================================================= -// -// MJP's DX11 Sample Framework -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -#pragma once - -#include "..\\PCH.h" - -#include "..\\InterfacePointers.h" -#include "..\\Utility.h" - -namespace SampleFramework11 -{ - -struct RenderTarget2D -{ - ID3D11Texture2DPtr Texture; - ID3D11RenderTargetViewPtr RTView; - ID3D11ShaderResourceViewPtr SRView; - ID3D11UnorderedAccessViewPtr UAView; - uint32 Width; - uint32 Height; - uint32 NumMipLevels; - uint32 MultiSamples; - uint32 MSQuality; - DXGI_FORMAT Format; - bool32 AutoGenMipMaps; - uint32 ArraySize; - bool32 CubeMap; - std::vector RTVArraySlices; - std::vector SRVArraySlices; - - RenderTarget2D(); - - void Initialize( ID3D11Device* device, - uint32 width, - uint32 height, - DXGI_FORMAT format, - uint32 numMipLevels = 1, - uint32 multiSamples = 1, - uint32 msQuality = 0, - bool32 autoGenMipMaps = false, - bool32 createUAV = false, - uint32 arraySize = 1, - bool32 cubeMap = false); -}; - -struct DepthStencilBuffer -{ - ID3D11Texture2DPtr Texture; - ID3D11DepthStencilViewPtr DSView; - ID3D11DepthStencilViewPtr ReadOnlyDSView; - ID3D11ShaderResourceViewPtr SRView; - uint32 Width; - uint32 Height; - uint32 MultiSamples; - uint32 MSQuality; - DXGI_FORMAT Format; - uint32 ArraySize; - bool32 CubeMap; - std::vector ArraySlices; - - DepthStencilBuffer(); - - void Initialize( ID3D11Device* device, - uint32 width, - uint32 height, - DXGI_FORMAT format = DXGI_FORMAT_D24_UNORM_S8_UINT, - bool32 useAsShaderResource = false, - uint32 multiSamples = 1, - uint32 msQuality = 0, - uint32 arraySize = 1, - bool32 cubeMap = false); -}; - -struct RWBuffer -{ - ID3D11BufferPtr Buffer; - ID3D11ShaderResourceViewPtr SRView; - ID3D11UnorderedAccessViewPtr UAView; - uint32 Size; - uint32 Stride; - uint32 NumElements; - bool32 RawBuffer; - DXGI_FORMAT Format; - - RWBuffer(); - - void Initialize(ID3D11Device* device, DXGI_FORMAT format, uint32 stride, uint32 numElements, bool32 rawBuffer = false, - bool vertexBuffer = false, bool indexBuffer = false, bool indirectArgs = false, - const void* initData = nullptr); -}; - -struct StagingBuffer -{ - ID3D11BufferPtr Buffer; - uint32 Size; - - StagingBuffer(); - - void Initialize(ID3D11Device* device, uint32 size); - void* Map(ID3D11DeviceContext* context); - void Unmap(ID3D11DeviceContext* context); -}; - -struct StagingTexture2D -{ - ID3D11Texture2DPtr Texture; - uint32 Width; - uint32 Height; - uint32 NumMipLevels; - uint32 MultiSamples; - uint32 MSQuality; - DXGI_FORMAT Format; - uint32 ArraySize; - - StagingTexture2D(); - - void Initialize( ID3D11Device* device, - uint32 width, - uint32 height, - DXGI_FORMAT format, - uint32 numMipLevels = 1, - uint32 multiSamples = 1, - uint32 msQuality = 0, - uint32 arraySize = 1); - - void* Map(ID3D11DeviceContext* context, uint32 subResourceIndex, uint32& pitch); - void Unmap(ID3D11DeviceContext* context, uint32 subResourceIndex); -}; - -struct StructuredBuffer -{ - ID3D11BufferPtr Buffer; - ID3D11ShaderResourceViewPtr SRView; - ID3D11UnorderedAccessViewPtr UAView; - uint32 Size; - uint32 Stride; - uint32 NumElements; - StagingBuffer DebugBuffer; - - StructuredBuffer(); - - void Initialize(ID3D11Device* device, uint32 stride, uint32 numElements, bool32 useAsUAV = false, - bool32 appendConsume = false, bool32 hiddenCounter = false, const void* initData = nullptr); - - void WriteToFile(const wchar* path, ID3D11Device* device, ID3D11DeviceContext* context); - void ReadFromFile(const wchar* path, ID3D11Device* device); - - template void DebugPrint(ID3D11DeviceContext* context, const char* name) - { - Assert_(Buffer != nullptr); - if(DebugBuffer.Size != Size) - { - ID3D11DevicePtr device; - context->GetDevice(&device); - DebugBuffer.Initialize(device, Size); - } - - std::printf("%s\n", name); - - context->CopyResource(DebugBuffer.Buffer, Buffer); - const T* data = reinterpret_cast(DebugBuffer.Map(context)); - for(uint32 i = 0; i < NumElements; ++i) - { - std::string elemPrint = data[i].Print(); - std::printf(" [%u] %s", i, elemPrint.c_str()); - } - } -}; - -template class ConstantBuffer -{ -public: - - T Data; - - ID3D11BufferPtr Buffer; - bool GPUWritable; - -public: - - ConstantBuffer() : GPUWritable(false) - { - ZeroMemory(&Data, sizeof(T)); - } - - void Initialize(ID3D11Device* device, bool gpuWritable = false) - { - D3D11_BUFFER_DESC desc; - desc.Usage = D3D11_USAGE_DYNAMIC; - desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - desc.MiscFlags = 0; - desc.ByteWidth = static_cast(sizeof(T) + (16 - (sizeof(T) % 16))); - - if(gpuWritable) - { - desc.Usage = D3D11_USAGE_DEFAULT; - desc.CPUAccessFlags = 0; - } - GPUWritable = gpuWritable; - - DXCall(device->CreateBuffer(&desc, nullptr, &Buffer)); - } - - void ApplyChanges(ID3D11DeviceContext* deviceContext) - { - Assert_(Buffer != nullptr); - - if(GPUWritable) - { - deviceContext->UpdateSubresource(Buffer, 0, nullptr, &Data, 0, 0); - } - else - { - D3D11_MAPPED_SUBRESOURCE mappedResource; - DXCall(deviceContext->Map(Buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource)); - CopyMemory(mappedResource.pData, &Data, sizeof(T)); - deviceContext->Unmap(Buffer, 0); - } - } - - void SetVS(ID3D11DeviceContext* deviceContext, uint32 slot) const - { - Assert_(Buffer != nullptr); - - ID3D11Buffer* bufferArray[1]; - bufferArray[0] = Buffer; - deviceContext->VSSetConstantBuffers(slot, 1, bufferArray); - } - - void SetPS(ID3D11DeviceContext* deviceContext, uint32 slot) const - { - Assert_(Buffer != nullptr); - - ID3D11Buffer* bufferArray[1]; - bufferArray[0] = Buffer; - deviceContext->PSSetConstantBuffers(slot, 1, bufferArray); - } - - void SetGS(ID3D11DeviceContext* deviceContext, uint32 slot) const - { - Assert_(Buffer != nullptr); - - ID3D11Buffer* bufferArray[1]; - bufferArray[0] = Buffer; - deviceContext->GSSetConstantBuffers(slot, 1, bufferArray); - } - - void SetHS(ID3D11DeviceContext* deviceContext, uint32 slot) const - { - Assert_(Buffer != nullptr); - - ID3D11Buffer* bufferArray[1]; - bufferArray[0] = Buffer; - deviceContext->HSSetConstantBuffers(slot, 1, bufferArray); - } - - void SetDS(ID3D11DeviceContext* deviceContext, uint32 slot) const - { - Assert_(Buffer != nullptr); - - ID3D11Buffer* bufferArray[1]; - bufferArray[0] = Buffer; - deviceContext->DSSetConstantBuffers(slot, 1, bufferArray); - } - - void SetCS(ID3D11DeviceContext* deviceContext, uint32 slot) const - { - Assert_(Buffer != nullptr); - - ID3D11Buffer* bufferArray[1]; - bufferArray[0] = Buffer; - deviceContext->CSSetConstantBuffers(slot, 1, bufferArray); - } -}; - -// For aligning to float4 boundaries -#define Float4Align __declspec(align(16)) - -class PIXEvent -{ -public: - - PIXEvent(const wchar* markerName) - { - D3DPERF_BeginEvent(0xFFFFFFFF, markerName); - } - - PIXEvent(const std::wstring& markerName) - { - D3DPERF_BeginEvent(0xFFFFFFFF, markerName.c_str()); - } - - ~PIXEvent() - { - D3DPERF_EndEvent(); - } -}; - +//================================================================================================= +// +// MJP's DX11 Sample Framework +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +#pragma once + +#include "..\\PCH.h" + +#include "..\\InterfacePointers.h" +#include "..\\Utility.h" +#include "..\\Containers.h" + +namespace SampleFramework11 +{ + +struct RenderTarget2D +{ + ID3D11Texture2DPtr Texture; + ID3D11RenderTargetViewPtr RTView; + ID3D11ShaderResourceViewPtr SRView; + ID3D11UnorderedAccessViewPtr UAView; + uint32 Width; + uint32 Height; + uint32 NumMipLevels; + uint32 MultiSamples; + uint32 MSQuality; + DXGI_FORMAT Format; + bool32 AutoGenMipMaps; + uint32 ArraySize; + bool32 CubeMap; + std::vector RTVArraySlices; + std::vector SRVArraySlices; + + RenderTarget2D(); + + void Initialize(ID3D11Device* device, + uint32 width, + uint32 height, + DXGI_FORMAT format, + uint32 numMipLevels = 1, + uint32 multiSamples = 1, + uint32 msQuality = 0, + bool32 autoGenMipMaps = false, + bool32 createUAV = false, + uint32 arraySize = 1, + bool32 cubeMap = false); +}; + +struct RenderTarget3D +{ + ID3D11Texture3DPtr Texture; + ID3D11ShaderResourceViewPtr SRView; + ID3D11UnorderedAccessViewPtr UAView; + uint32 Width = 0; + uint32 Height = 0; + uint32 Depth = 0; + uint32 NumMipLevels = 0; + DXGI_FORMAT Format; + FixedArray MipSRVs; + FixedArray MipUAVs; + + void Initialize(ID3D11Device* device, + uint32 width, + uint32 height, + uint32 depth, + DXGI_FORMAT format, + uint32 numMipLevels, + bool32 createUAV); +}; + +struct DepthStencilBuffer +{ + ID3D11Texture2DPtr Texture; + ID3D11DepthStencilViewPtr DSView; + ID3D11DepthStencilViewPtr ReadOnlyDSView; + ID3D11ShaderResourceViewPtr SRView; + uint32 Width; + uint32 Height; + uint32 MultiSamples; + uint32 MSQuality; + DXGI_FORMAT Format; + uint32 ArraySize; + bool32 CubeMap; + std::vector ArraySlices; + + DepthStencilBuffer(); + + void Initialize( ID3D11Device* device, + uint32 width, + uint32 height, + DXGI_FORMAT format = DXGI_FORMAT_D24_UNORM_S8_UINT, + bool32 useAsShaderResource = false, + uint32 multiSamples = 1, + uint32 msQuality = 0, + uint32 arraySize = 1, + bool32 cubeMap = false); +}; + +struct RWBuffer +{ + ID3D11BufferPtr Buffer; + ID3D11ShaderResourceViewPtr SRView; + ID3D11UnorderedAccessViewPtr UAView; + uint32 Size; + uint32 Stride; + uint32 NumElements; + bool32 RawBuffer; + DXGI_FORMAT Format; + + RWBuffer(); + + void Initialize(ID3D11Device* device, DXGI_FORMAT format, uint32 stride, uint32 numElements, bool32 rawBuffer = false, + bool vertexBuffer = false, bool indexBuffer = false, bool indirectArgs = false, + const void* initData = nullptr); +}; + +struct StagingBuffer +{ + ID3D11BufferPtr Buffer; + uint32 Size; + + StagingBuffer(); + + void Initialize(ID3D11Device* device, uint32 size); + void* Map(ID3D11DeviceContext* context); + void Unmap(ID3D11DeviceContext* context); +}; + +struct StagingTexture2D +{ + ID3D11Texture2DPtr Texture; + uint32 Width; + uint32 Height; + uint32 NumMipLevels; + uint32 MultiSamples; + uint32 MSQuality; + DXGI_FORMAT Format; + uint32 ArraySize; + + StagingTexture2D(); + + void Initialize( ID3D11Device* device, + uint32 width, + uint32 height, + DXGI_FORMAT format, + uint32 numMipLevels = 1, + uint32 multiSamples = 1, + uint32 msQuality = 0, + uint32 arraySize = 1); + + void* Map(ID3D11DeviceContext* context, uint32 subResourceIndex, uint32& pitch); + void Unmap(ID3D11DeviceContext* context, uint32 subResourceIndex); +}; + +struct StructuredBuffer +{ + ID3D11BufferPtr Buffer; + ID3D11ShaderResourceViewPtr SRView; + ID3D11UnorderedAccessViewPtr UAView; + uint32 Size; + uint32 Stride; + uint32 NumElements; + StagingBuffer DebugBuffer; + + StructuredBuffer(); + + void Initialize(ID3D11Device* device, uint32 stride, uint32 numElements, bool32 useAsUAV = false, + bool32 appendConsume = false, bool32 hiddenCounter = false, const void* initData = nullptr); + + void WriteToFile(const wchar* path, ID3D11Device* device, ID3D11DeviceContext* context); + void ReadFromFile(const wchar* path, ID3D11Device* device); + + template void DebugPrint(ID3D11DeviceContext* context, const char* name) + { + Assert_(Buffer != nullptr); + if(DebugBuffer.Size != Size) + { + ID3D11DevicePtr device; + context->GetDevice(&device); + DebugBuffer.Initialize(device, Size); + } + + std::printf("%s\n", name); + + context->CopyResource(DebugBuffer.Buffer, Buffer); + const T* data = reinterpret_cast(DebugBuffer.Map(context)); + for(uint32 i = 0; i < NumElements; ++i) + { + std::string elemPrint = data[i].Print(); + std::printf(" [%u] %s", i, elemPrint.c_str()); + } + } +}; + +template class ConstantBuffer +{ +public: + + T Data; + + ID3D11BufferPtr Buffer; + bool GPUWritable; + +public: + + ConstantBuffer() : GPUWritable(false) + { + ZeroMemory(&Data, sizeof(T)); + } + + void Initialize(ID3D11Device* device, bool gpuWritable = false) + { + D3D11_BUFFER_DESC desc; + desc.Usage = D3D11_USAGE_DYNAMIC; + desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + desc.MiscFlags = 0; + desc.ByteWidth = static_cast(sizeof(T) + (16 - (sizeof(T) % 16))); + + if(gpuWritable) + { + desc.Usage = D3D11_USAGE_DEFAULT; + desc.CPUAccessFlags = 0; + } + GPUWritable = gpuWritable; + + DXCall(device->CreateBuffer(&desc, nullptr, &Buffer)); + } + + void ApplyChanges(ID3D11DeviceContext* deviceContext) + { + Assert_(Buffer != nullptr); + + if(GPUWritable) + { + deviceContext->UpdateSubresource(Buffer, 0, nullptr, &Data, 0, 0); + } + else + { + D3D11_MAPPED_SUBRESOURCE mappedResource; + DXCall(deviceContext->Map(Buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource)); + CopyMemory(mappedResource.pData, &Data, sizeof(T)); + deviceContext->Unmap(Buffer, 0); + } + } + + void SetVS(ID3D11DeviceContext* deviceContext, uint32 slot) const + { + Assert_(Buffer != nullptr); + + ID3D11Buffer* bufferArray[1]; + bufferArray[0] = Buffer; + deviceContext->VSSetConstantBuffers(slot, 1, bufferArray); + } + + void SetPS(ID3D11DeviceContext* deviceContext, uint32 slot) const + { + Assert_(Buffer != nullptr); + + ID3D11Buffer* bufferArray[1]; + bufferArray[0] = Buffer; + deviceContext->PSSetConstantBuffers(slot, 1, bufferArray); + } + + void SetGS(ID3D11DeviceContext* deviceContext, uint32 slot) const + { + Assert_(Buffer != nullptr); + + ID3D11Buffer* bufferArray[1]; + bufferArray[0] = Buffer; + deviceContext->GSSetConstantBuffers(slot, 1, bufferArray); + } + + void SetHS(ID3D11DeviceContext* deviceContext, uint32 slot) const + { + Assert_(Buffer != nullptr); + + ID3D11Buffer* bufferArray[1]; + bufferArray[0] = Buffer; + deviceContext->HSSetConstantBuffers(slot, 1, bufferArray); + } + + void SetDS(ID3D11DeviceContext* deviceContext, uint32 slot) const + { + Assert_(Buffer != nullptr); + + ID3D11Buffer* bufferArray[1]; + bufferArray[0] = Buffer; + deviceContext->DSSetConstantBuffers(slot, 1, bufferArray); + } + + void SetCS(ID3D11DeviceContext* deviceContext, uint32 slot) const + { + Assert_(Buffer != nullptr); + + ID3D11Buffer* bufferArray[1]; + bufferArray[0] = Buffer; + deviceContext->CSSetConstantBuffers(slot, 1, bufferArray); + } +}; + +// For aligning to float4 boundaries +#define Float4Align __declspec(align(16)) + +class PIXEvent +{ +public: + + PIXEvent(const wchar* markerName) + { + D3DPERF_BeginEvent(0xFFFFFFFF, markerName); + } + + PIXEvent(const std::wstring& markerName) + { + D3DPERF_BeginEvent(0xFFFFFFFF, markerName.c_str()); + } + + ~PIXEvent() + { + D3DPERF_EndEvent(); + } +}; + } \ No newline at end of file diff --git a/SampleFramework11/v1.02/Graphics/SH.cpp b/SampleFramework11/v1.02/Graphics/SH.cpp index c38f265..1896feb 100644 --- a/SampleFramework11/v1.02/Graphics/SH.cpp +++ b/SampleFramework11/v1.02/Graphics/SH.cpp @@ -24,9 +24,9 @@ SH4 ProjectOntoSH4(const Float3& dir) sh.Coefficients[0] = 0.282095f; // Band 1 - sh.Coefficients[1] = 0.488603f * dir.y; + sh.Coefficients[1] = -0.488603f * dir.y; sh.Coefficients[2] = 0.488603f * dir.z; - sh.Coefficients[3] = 0.488603f * dir.x; + sh.Coefficients[3] = -0.488603f * dir.x; return sh; } @@ -64,15 +64,15 @@ SH9 ProjectOntoSH9(const Float3& dir) sh.Coefficients[0] = 0.282095f; // Band 1 - sh.Coefficients[1] = 0.488603f * dir.y; + sh.Coefficients[1] = -0.488603f * dir.y; sh.Coefficients[2] = 0.488603f * dir.z; - sh.Coefficients[3] = 0.488603f * dir.x; + sh.Coefficients[3] = -0.488603f * dir.x; // Band 2 sh.Coefficients[4] = 1.092548f * dir.x * dir.y; - sh.Coefficients[5] = 1.092548f * dir.y * dir.z; + sh.Coefficients[5] = -1.092548f * dir.y * dir.z; sh.Coefficients[6] = 0.315392f * (3.0f * dir.z * dir.z - 1.0f); - sh.Coefficients[7] = 1.092548f * dir.x * dir.z; + sh.Coefficients[7] = -1.092548f * dir.x * dir.z; sh.Coefficients[8] = 0.546274f * (dir.x * dir.x - dir.y * dir.y); return sh; @@ -111,12 +111,12 @@ H4 ProjectOntoH4(const Float3& dir) { H4 result; - result[0] = (1.0f / std::sqrt(2.0f * 3.14159f)); + result[0] = (1.0f / sqrt(2.0f * 3.14159f)); // Band 1 - result[1] = std::sqrt(1.5f / 3.14159f) * dir.y; - result[2] = std::sqrt(1.5f / 3.14159f) * (2 * dir.z - 1.0f); - result[3] = std::sqrt(1.5f / 3.14159f) * dir.x; + result[1] = -sqrt(1.5f / 3.14159f) * dir.y; + result[2] = sqrt(1.5f / 3.14159f) * (2 * dir.z - 1.0f); + result[3] = -sqrt(1.5f / 3.14159f) * dir.x; return result; } diff --git a/SampleFramework11/v1.02/Graphics/Skybox.cpp b/SampleFramework11/v1.02/Graphics/Skybox.cpp index b4a9a0b..8ab850d 100644 --- a/SampleFramework11/v1.02/Graphics/Skybox.cpp +++ b/SampleFramework11/v1.02/Graphics/Skybox.cpp @@ -1,426 +1,447 @@ -//================================================================================================= -// -// MJP's DX11 Sample Framework -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -#include "PCH.h" - -#include "Skybox.h" - -#include "..\\Utility.h" -#include "ShaderCompilation.h" -#include "Textures.h" -#include "Math.h" - -namespace SampleFramework11 -{ - -static float AngleBetween(const Float3& dir0, const Float3& dir1) -{ - return std::acos(std::max(Float3::Dot(dir0, dir1), 0.00001f)); -} - -void SkyCache::Init(Float3 sunDirection, Float3 groundAlbedo, float turbidity) -{ - sunDirection.y = Saturate(sunDirection.y); - sunDirection = Float3::Normalize(sunDirection); - turbidity = Clamp(turbidity, 1.0f, 32.0f); - groundAlbedo = Saturate(groundAlbedo); - - if(StateR != nullptr && sunDirection == SunDirection - && groundAlbedo == Albedo && turbidity == Turbidity) - return; - - Shutdown(); - - float thetaS = AngleBetween(sunDirection, Float3(0, 1, 0)); - float elevation = Pi_2 - thetaS; - StateR = arhosek_rgb_skymodelstate_alloc_init(turbidity, groundAlbedo.x, elevation); - StateG = arhosek_rgb_skymodelstate_alloc_init(turbidity, groundAlbedo.y, elevation); - StateB = arhosek_rgb_skymodelstate_alloc_init(turbidity, groundAlbedo.z, elevation); - - Albedo = groundAlbedo; - Elevation = elevation; - SunDirection = sunDirection; - Turbidity = turbidity; -} - -void SkyCache::Shutdown() -{ - if(StateR != nullptr) - { - arhosekskymodelstate_free(StateR); - StateR = nullptr; - } - - if(StateG != nullptr) - { - arhosekskymodelstate_free(StateG); - StateG = nullptr; - } - - if(StateB != nullptr) - { - arhosekskymodelstate_free(StateB); - StateB = nullptr; - } - - CubeMap = nullptr; - Turbidity = 0.0f; - Albedo = 0.0f; - Elevation = 0.0f; - SunDirection = 0.0f; -} - -SkyCache::~SkyCache() -{ - Shutdown(); -} - -Skybox::Skybox() -{ -} - -Skybox::~Skybox() -{ -} - -void Skybox::Initialize(ID3D11Device* device_) -{ - device = device_; - - // Load the shaders - const std::wstring shaderPath = SampleFrameworkDir() + L"Shaders\\Skybox.hlsl"; - vertexShader = CompileVSFromFile(device, shaderPath.c_str(), "SkyboxVS", "vs_5_0"); - emPixelShader = CompilePSFromFile(device, shaderPath.c_str(), "SkyboxPS", "ps_5_0"); - simpleSkyPS = CompilePSFromFile(device, shaderPath.c_str(), "SimpleSkyPS", "ps_5_0"); - - // Create the input layout - D3D11_INPUT_ELEMENT_DESC layout[] = - { - { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, - }; - - ID3DBlob* byteCode = vertexShader->ByteCode; - DXCall(device->CreateInputLayout(layout, 1, byteCode->GetBufferPointer(), byteCode->GetBufferSize(), &inputLayout)); - - // Create and initialize the vertex and index buffers - Float3 verts[NumVertices] = - { - Float3(-1, 1, 1), - Float3(1, 1, 1), - Float3(1, -1, 1), - Float3(-1, -1, 1), - Float3(1, 1, -1), - Float3(-1, 1, -1), - Float3(-1, -1, -1), - Float3(1, -1,- 1), - }; - - D3D11_BUFFER_DESC desc; - desc.Usage = D3D11_USAGE_IMMUTABLE; - desc.ByteWidth = sizeof(verts); - desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; - desc.CPUAccessFlags = 0; - desc.MiscFlags = 0; - D3D11_SUBRESOURCE_DATA initData; - initData.pSysMem = verts; - initData.SysMemPitch = 0; - initData.SysMemSlicePitch = 0; - DXCall(device->CreateBuffer(&desc, &initData, &vertexBuffer)); - - unsigned short indices[NumIndices] = - { - 0, 1, 2, 2, 3, 0, // Front - 1, 4, 7, 7, 2, 1, // Right - 4, 5, 6, 6, 7, 4, // Back - 5, 0, 3, 3, 6, 5, // Left - 5, 4, 1, 1, 0, 5, // Top - 3, 2, 7, 7, 6, 3 // Bottom - }; - - desc.Usage = D3D11_USAGE_IMMUTABLE; - desc.ByteWidth = sizeof(indices); - desc.BindFlags = D3D11_BIND_INDEX_BUFFER; - desc.CPUAccessFlags = 0; - initData.pSysMem = indices; - DXCall(device->CreateBuffer(&desc, &initData, &indexBuffer)); - - // Create the VS constant buffer - vsConstantBuffer.Initialize(device, false); - - // Create the PS constant buffer - psConstantBuffer.Initialize(device, false); - - // Create a depth-stencil state - D3D11_DEPTH_STENCIL_DESC dsDesc; - dsDesc.DepthEnable = true; - dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; - dsDesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL; - dsDesc.StencilEnable = false; - dsDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; - dsDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; - dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; - dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; - dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; - dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; - dsDesc.BackFace = dsDesc.FrontFace; - DXCall(device->CreateDepthStencilState(&dsDesc, &dsState)); - - // Create a blend state - D3D11_BLEND_DESC blendDesc; - blendDesc.AlphaToCoverageEnable = false; - blendDesc.IndependentBlendEnable = false; - for (UINT i = 0; i < 8; ++i) - { - blendDesc.RenderTarget[i].BlendEnable = false; - blendDesc.RenderTarget[i].BlendOp = D3D11_BLEND_OP_ADD; - blendDesc.RenderTarget[i].BlendOpAlpha = D3D11_BLEND_OP_ADD; - blendDesc.RenderTarget[i].DestBlend = D3D11_BLEND_ONE; - blendDesc.RenderTarget[i].DestBlendAlpha = D3D11_BLEND_ONE; - blendDesc.RenderTarget[i].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; - blendDesc.RenderTarget[i].SrcBlend = D3D11_BLEND_ONE; - blendDesc.RenderTarget[i].SrcBlendAlpha = D3D11_BLEND_ONE; - } - DXCall(device->CreateBlendState(&blendDesc, &blendState)); - - // Create a rasterizer state - D3D11_RASTERIZER_DESC rastDesc; - rastDesc.AntialiasedLineEnable = false; - rastDesc.CullMode = D3D11_CULL_NONE; - rastDesc.DepthBias = 0; - rastDesc.DepthBiasClamp = 0.0f; - rastDesc.DepthClipEnable = true; - rastDesc.FillMode = D3D11_FILL_SOLID; - rastDesc.FrontCounterClockwise = false; - rastDesc.MultisampleEnable = true; - rastDesc.ScissorEnable = false; - rastDesc.SlopeScaledDepthBias = 0; - DXCall(device->CreateRasterizerState(&rastDesc, &rastState)); - - D3D11_SAMPLER_DESC sampDesc; - sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; - sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; - sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; - sampDesc.BorderColor[0] = 0; - sampDesc.BorderColor[1] = 0; - sampDesc.BorderColor[2] = 0; - sampDesc.BorderColor[3] = 0; - sampDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; - sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; - sampDesc.MaxAnisotropy = 1; - sampDesc.MaxLOD = D3D11_FLOAT32_MAX; - sampDesc.MinLOD = 0; - sampDesc.MipLODBias = 0; - DXCall(device->CreateSamplerState(&sampDesc, &samplerState)); -} - -void Skybox::RenderCommon(ID3D11DeviceContext* context, - ID3D11ShaderResourceView* environmentMap, - ID3D11PixelShader* ps, - const Float4x4& view, - const Float4x4& projection, - Float3 scale) -{ - float blendFactor[4] = {1, 1, 1, 1}; - context->RSSetState(rastState); - context->OMSetBlendState(blendState, blendFactor, 0xFFFFFFFF); - context->OMSetDepthStencilState(dsState, 0); - context->PSSetSamplers(0, 1, &(samplerState.GetInterfacePtr())); - - // Get the viewports - UINT numViewports = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; - D3D11_VIEWPORT oldViewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; - context->RSGetViewports(&numViewports, oldViewports); - - // Set a viewport with MinZ pushed back - D3D11_VIEWPORT newViewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; - for(UINT i = 0; i < numViewports; ++i) - { - newViewports[i] = oldViewports[0]; - newViewports[i].MinDepth = 1.0f; - newViewports[i].MaxDepth = 1.0f; - } - context->RSSetViewports(numViewports, newViewports); - - // Set the input layout - context->IASetInputLayout(inputLayout); - - // Set the vertex buffer - UINT stride = sizeof(XMFLOAT3); - UINT offset = 0; - ID3D11Buffer* vertexBuffers[1] = { vertexBuffer.GetInterfacePtr() }; - context->IASetVertexBuffers(0, 1, vertexBuffers, &stride, &offset); - - // Set the index buffer - context->IASetIndexBuffer(indexBuffer, DXGI_FORMAT_R16_UINT, 0); - - // Set primitive topology - context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - - // Set the shaders - context->VSSetShader(vertexShader, nullptr, 0); - context->PSSetShader(ps, nullptr, 0); - context->GSSetShader(nullptr, nullptr, 0); - context->DSSetShader(nullptr, nullptr, 0); - context->HSSetShader(nullptr, nullptr, 0); - - // Set the constants - vsConstantBuffer.Data.View = Float4x4::Transpose(view); - vsConstantBuffer.Data.Projection = Float4x4::Transpose(projection); - vsConstantBuffer.ApplyChanges(context); - vsConstantBuffer.SetVS(context, 0); - - psConstantBuffer.Data.Scale = scale; - psConstantBuffer.ApplyChanges(context); - psConstantBuffer.SetPS(context, 0); - - // Set the texture - ID3D11ShaderResourceView* srViews[1] = { environmentMap }; - context->PSSetShaderResources(0, 1, srViews); - - // Draw - context->DrawIndexed(NumIndices, 0, 0); - - // Set the viewport back to what it was - context->RSSetViewports(numViewports, oldViewports); -} - -void Skybox::RenderEnvironmentMap(ID3D11DeviceContext* context, - ID3D11ShaderResourceView* environmentMap, - const Float4x4& view, - const Float4x4& projection, - Float3 scale) -{ - PIXEvent pixEvent(L"Skybox Render Environment Map"); - - psConstantBuffer.Data.EnableSun = false; - RenderCommon(context, environmentMap, emPixelShader, view, projection, scale); -} - -void Skybox::RenderSky(ID3D11DeviceContext* context, - Float3 sunDirection, - Float3 groundAlbedo, - Float3 sunColor, - float sunSize, - float turbidity, - const Float4x4& view, - const Float4x4& projection, - Float3 scale) -{ - PIXEvent pixEvent(L"Skybox Render Sky"); - - // Update the cache, if necessary - skyCache.Init(sunDirection, groundAlbedo, turbidity); - - if(skyCache.CubeMap == nullptr) - { - const uint64 CubeMapRes = 128; - std::vector texels; - texels.resize(CubeMapRes * CubeMapRes * 6); - - for(uint64 s = 0; s < 6; ++s) - { - for(uint64 y = 0; y < CubeMapRes; ++y) - { - for(uint64 x = 0; x < CubeMapRes; ++x) - { - Float3 dir = MapXYSToDirection(x, y, s, CubeMapRes, CubeMapRes); - Float3 radiance = SampleSky(skyCache, dir); - - uint64 idx = (s * CubeMapRes * CubeMapRes) + (y * CubeMapRes) + x; - texels[idx] = Half4(Float4(radiance, 1.0f)); - } - } - } - - D3D11_TEXTURE2D_DESC desc; - desc.Width = uint32(CubeMapRes); - desc.Height = uint32(CubeMapRes); - desc.ArraySize = 6; - desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - desc.CPUAccessFlags = 0; - desc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; - desc.MipLevels = 1; - desc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_IMMUTABLE; - - D3D11_SUBRESOURCE_DATA resData[6]; - for(uint64 i = 0; i < 6; ++i) - { - resData[i].pSysMem = &texels[i * CubeMapRes * CubeMapRes]; - resData[i].SysMemPitch = sizeof(texels[0]) * CubeMapRes; - resData[i].SysMemSlicePitch = 0; - } - - ID3D11DevicePtr device; - context->GetDevice(&device); - - ID3D11Texture2DPtr texture; - DXCall(device->CreateTexture2D(&desc, resData, &texture)); - DXCall(device->CreateShaderResourceView(texture, nullptr, &skyCache.CubeMap)); - } - - // Set the pixel shader constants - bool enableSun = sunSize > 0.0f && sunColor.x > 0.0f && sunColor.y > 0.0f && sunColor.z > 0.0f; - psConstantBuffer.Data.SunDirection = sunDirection; - psConstantBuffer.Data.EnableSun = enableSun ? 1 : 0; - psConstantBuffer.Data.SunColor = sunColor; - psConstantBuffer.Data.Scale = scale; - psConstantBuffer.Data.CosSunAngularRadius = std::cos(DegToRad(sunSize)); - - RenderCommon(context, skyCache.CubeMap, emPixelShader, view, projection, scale); -} - -void Skybox::RenderSimpleSky(ID3D11DeviceContext* context, - Float3 skyColor, - Float3 sunDirection, - Float3 sunColor, - float sunSize, - const Float4x4& view, - const Float4x4& projection, - Float3 scale) -{ - PIXEvent pixEvent(L"Skybox Render Simple Sky"); - - // Set the pixel shader constants - bool enableSun = sunSize > 0.0f && sunColor.x > 0.0f && sunColor.y > 0.0f && sunColor.z > 0.0f; - psConstantBuffer.Data.SkyColor = skyColor; - psConstantBuffer.Data.SunDirection = sunDirection; - psConstantBuffer.Data.EnableSun = enableSun ? 1 : 0; - psConstantBuffer.Data.SunColor = sunColor; - psConstantBuffer.Data.Scale = scale; - psConstantBuffer.Data.CosSunAngularRadius = std::cos(DegToRad(sunSize)); - - RenderCommon(context, nullptr, simpleSkyPS, view, projection, scale); -} - -Float3 Skybox::SampleSky(const SkyCache& cache, Float3 sampleDir) -{ - Assert_(cache.StateR != nullptr); - - float gamma = AngleBetween(sampleDir, cache.SunDirection); - float theta = AngleBetween(sampleDir, Float3(0, 1, 0)); - - Float3 radiance; - - radiance.x = float(arhosek_tristim_skymodel_radiance(cache.StateR, theta, gamma, 0)); - radiance.y = float(arhosek_tristim_skymodel_radiance(cache.StateG, theta, gamma, 1)); - radiance.z = float(arhosek_tristim_skymodel_radiance(cache.StateB, theta, gamma, 2)); - - // Multiply by standard luminous efficacy of 683 lm/W to bring us in line with the photometric - // units used during rendering - radiance *= 683.0f; - - radiance *= FP16Scale; - - return radiance; -} - -} +//================================================================================================= +// +// MJP's DX11 Sample Framework +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +#include "PCH.h" + +#include "Skybox.h" + +#include "..\\Utility.h" +#include "ShaderCompilation.h" +#include "Textures.h" +#include "Math.h" + +namespace SampleFramework11 +{ + +static float AngleBetween(const Float3& dir0, const Float3& dir1) +{ + return std::acos(std::max(Float3::Dot(dir0, dir1), 0.00001f)); +} + +void SkyCache::Init(Float3 sunDirection, Float3 groundAlbedo, float turbidity) +{ + sunDirection.y = Saturate(sunDirection.y); + sunDirection = Float3::Normalize(sunDirection); + turbidity = Clamp(turbidity, 1.0f, 32.0f); + groundAlbedo = Saturate(groundAlbedo); + + if(StateR != nullptr && sunDirection == SunDirection + && groundAlbedo == Albedo && turbidity == Turbidity) + return; + + Shutdown(); + + float thetaS = AngleBetween(sunDirection, Float3(0, 1, 0)); + float elevation = Pi_2 - thetaS; + StateR = arhosek_rgb_skymodelstate_alloc_init(turbidity, groundAlbedo.x, elevation); + StateG = arhosek_rgb_skymodelstate_alloc_init(turbidity, groundAlbedo.y, elevation); + StateB = arhosek_rgb_skymodelstate_alloc_init(turbidity, groundAlbedo.z, elevation); + + Albedo = groundAlbedo; + Elevation = elevation; + SunDirection = sunDirection; + Turbidity = turbidity; +} + +void SkyCache::Shutdown() +{ + if(StateR != nullptr) + { + arhosekskymodelstate_free(StateR); + StateR = nullptr; + } + + if(StateG != nullptr) + { + arhosekskymodelstate_free(StateG); + StateG = nullptr; + } + + if(StateB != nullptr) + { + arhosekskymodelstate_free(StateB); + StateB = nullptr; + } + + CubeMap = nullptr; + Turbidity = 0.0f; + Albedo = 0.0f; + Elevation = 0.0f; + SunDirection = 0.0f; +} + +SkyCache::~SkyCache() +{ + Shutdown(); +} + +Skybox::Skybox() +{ +} + +Skybox::~Skybox() +{ +} + +void Skybox::Initialize(ID3D11Device* device_) +{ + device = device_; + + // Load the shaders + const std::wstring shaderPath = SampleFrameworkDir() + L"Shaders\\Skybox.hlsl"; + vertexShader = CompileVSFromFile(device, shaderPath.c_str(), "SkyboxVS", "vs_5_0"); + emPixelShader = CompilePSFromFile(device, shaderPath.c_str(), "SkyboxPS", "ps_5_0"); + simpleSkyPS = CompilePSFromFile(device, shaderPath.c_str(), "SimpleSkyPS", "ps_5_0"); + + // Create the input layout + D3D11_INPUT_ELEMENT_DESC layout[] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + + ID3DBlob* byteCode = vertexShader->ByteCode; + DXCall(device->CreateInputLayout(layout, 1, byteCode->GetBufferPointer(), byteCode->GetBufferSize(), &inputLayout)); + + // Create and initialize the vertex and index buffers + Float3 verts[NumVertices] = + { + Float3(-1, 1, 1), + Float3(1, 1, 1), + Float3(1, -1, 1), + Float3(-1, -1, 1), + Float3(1, 1, -1), + Float3(-1, 1, -1), + Float3(-1, -1, -1), + Float3(1, -1,- 1), + }; + + D3D11_BUFFER_DESC desc; + desc.Usage = D3D11_USAGE_IMMUTABLE; + desc.ByteWidth = sizeof(verts); + desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + D3D11_SUBRESOURCE_DATA initData; + initData.pSysMem = verts; + initData.SysMemPitch = 0; + initData.SysMemSlicePitch = 0; + DXCall(device->CreateBuffer(&desc, &initData, &vertexBuffer)); + + unsigned short indices[NumIndices] = + { + 0, 1, 2, 2, 3, 0, // Front + 1, 4, 7, 7, 2, 1, // Right + 4, 5, 6, 6, 7, 4, // Back + 5, 0, 3, 3, 6, 5, // Left + 5, 4, 1, 1, 0, 5, // Top + 3, 2, 7, 7, 6, 3 // Bottom + }; + + desc.Usage = D3D11_USAGE_IMMUTABLE; + desc.ByteWidth = sizeof(indices); + desc.BindFlags = D3D11_BIND_INDEX_BUFFER; + desc.CPUAccessFlags = 0; + initData.pSysMem = indices; + DXCall(device->CreateBuffer(&desc, &initData, &indexBuffer)); + + // Create the VS constant buffer + vsConstantBuffer.Initialize(device, false); + + // Create the PS constant buffer + psConstantBuffer.Initialize(device, false); + + // Create a depth-stencil state + D3D11_DEPTH_STENCIL_DESC dsDesc; + dsDesc.DepthEnable = true; + dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; + dsDesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL; + dsDesc.StencilEnable = false; + dsDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; + dsDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; + dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; + dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + dsDesc.BackFace = dsDesc.FrontFace; + DXCall(device->CreateDepthStencilState(&dsDesc, &dsState)); + + // Create a blend state + D3D11_BLEND_DESC blendDesc; + blendDesc.AlphaToCoverageEnable = false; + blendDesc.IndependentBlendEnable = false; + for (UINT i = 0; i < 8; ++i) + { + blendDesc.RenderTarget[i].BlendEnable = false; + blendDesc.RenderTarget[i].BlendOp = D3D11_BLEND_OP_ADD; + blendDesc.RenderTarget[i].BlendOpAlpha = D3D11_BLEND_OP_ADD; + blendDesc.RenderTarget[i].DestBlend = D3D11_BLEND_ONE; + blendDesc.RenderTarget[i].DestBlendAlpha = D3D11_BLEND_ONE; + blendDesc.RenderTarget[i].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + blendDesc.RenderTarget[i].SrcBlend = D3D11_BLEND_ONE; + blendDesc.RenderTarget[i].SrcBlendAlpha = D3D11_BLEND_ONE; + } + DXCall(device->CreateBlendState(&blendDesc, &blendState)); + + // Create a rasterizer state + D3D11_RASTERIZER_DESC rastDesc; + rastDesc.AntialiasedLineEnable = false; + rastDesc.CullMode = D3D11_CULL_NONE; + rastDesc.DepthBias = 0; + rastDesc.DepthBiasClamp = 0.0f; + rastDesc.DepthClipEnable = true; + rastDesc.FillMode = D3D11_FILL_SOLID; + rastDesc.FrontCounterClockwise = false; + rastDesc.MultisampleEnable = true; + rastDesc.ScissorEnable = false; + rastDesc.SlopeScaledDepthBias = 0; + DXCall(device->CreateRasterizerState(&rastDesc, &rastState)); + + D3D11_SAMPLER_DESC sampDesc; + sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; + sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; + sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; + sampDesc.BorderColor[0] = 0; + sampDesc.BorderColor[1] = 0; + sampDesc.BorderColor[2] = 0; + sampDesc.BorderColor[3] = 0; + sampDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; + sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + sampDesc.MaxAnisotropy = 1; + sampDesc.MaxLOD = D3D11_FLOAT32_MAX; + sampDesc.MinLOD = 0; + sampDesc.MipLODBias = 0; + DXCall(device->CreateSamplerState(&sampDesc, &samplerState)); +} + +void Skybox::RenderCommon(ID3D11DeviceContext* context, + ID3D11ShaderResourceView* environmentMap, + ID3D11PixelShader* ps, + const Float4x4& view, + const Float4x4& projection, + Float3 scale) +{ + float blendFactor[4] = {1, 1, 1, 1}; + context->RSSetState(rastState); + context->OMSetBlendState(blendState, blendFactor, 0xFFFFFFFF); + context->OMSetDepthStencilState(dsState, 0); + context->PSSetSamplers(0, 1, &(samplerState.GetInterfacePtr())); + + // Get the viewports + UINT numViewports = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; + D3D11_VIEWPORT oldViewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; + context->RSGetViewports(&numViewports, oldViewports); + + // Set a viewport with MinZ pushed back + D3D11_VIEWPORT newViewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; + for(UINT i = 0; i < numViewports; ++i) + { + newViewports[i] = oldViewports[0]; + newViewports[i].MinDepth = 1.0f; + newViewports[i].MaxDepth = 1.0f; + } + context->RSSetViewports(numViewports, newViewports); + + // Set the input layout + context->IASetInputLayout(inputLayout); + + // Set the vertex buffer + UINT stride = sizeof(XMFLOAT3); + UINT offset = 0; + ID3D11Buffer* vertexBuffers[1] = { vertexBuffer.GetInterfacePtr() }; + context->IASetVertexBuffers(0, 1, vertexBuffers, &stride, &offset); + + // Set the index buffer + context->IASetIndexBuffer(indexBuffer, DXGI_FORMAT_R16_UINT, 0); + + // Set primitive topology + context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + // Set the shaders + context->VSSetShader(vertexShader, nullptr, 0); + context->PSSetShader(ps, nullptr, 0); + context->GSSetShader(nullptr, nullptr, 0); + context->DSSetShader(nullptr, nullptr, 0); + context->HSSetShader(nullptr, nullptr, 0); + + // Set the constants + vsConstantBuffer.Data.View = Float4x4::Transpose(view); + vsConstantBuffer.Data.Projection = Float4x4::Transpose(projection); + vsConstantBuffer.ApplyChanges(context); + vsConstantBuffer.SetVS(context, 0); + + psConstantBuffer.Data.Scale = scale; + psConstantBuffer.ApplyChanges(context); + psConstantBuffer.SetPS(context, 0); + + // Set the texture + ID3D11ShaderResourceView* srViews[1] = { environmentMap }; + context->PSSetShaderResources(0, 1, srViews); + + // Draw + context->DrawIndexed(NumIndices, 0, 0); + + // Set the viewport back to what it was + context->RSSetViewports(numViewports, oldViewports); +} + +void Skybox::RenderEnvironmentMap(ID3D11DeviceContext* context, + ID3D11ShaderResourceView* environmentMap, + const Float4x4& view, + const Float4x4& projection, + Float3 scale) +{ + PIXEvent pixEvent(L"Skybox Render Environment Map"); + + psConstantBuffer.Data.EnableSun = false; + RenderCommon(context, environmentMap, emPixelShader, view, projection, scale); +} + +void Skybox::RenderSky(ID3D11DeviceContext* context, + Float3 sunDirection, + Float3 groundAlbedo, + Float3 sunColor, + float sunSize, + float turbidity, + const Float4x4& view, + const Float4x4& projection, + Float3 scale) +{ + PIXEvent pixEvent(L"Skybox Render Sky"); + + // Update the cache, if necessary + ID3D11DevicePtr device; + context->GetDevice(&device); + UpdateSkyCache(device, sunDirection, groundAlbedo, turbidity); + + // Set the pixel shader constants + bool enableSun = sunSize > 0.0f && sunColor.x > 0.0f && sunColor.y > 0.0f && sunColor.z > 0.0f; + psConstantBuffer.Data.SunDirection = sunDirection; + psConstantBuffer.Data.EnableSun = enableSun ? 1 : 0; + psConstantBuffer.Data.SunColor = sunColor; + psConstantBuffer.Data.Scale = scale; + psConstantBuffer.Data.CosSunAngularRadius = std::cos(DegToRad(sunSize)); + + RenderCommon(context, skyCache.CubeMap, emPixelShader, view, projection, scale); +} + +void Skybox::RenderSimpleSky(ID3D11DeviceContext* context, + Float3 skyColor, + Float3 sunDirection, + Float3 sunColor, + float sunSize, + const Float4x4& view, + const Float4x4& projection, + Float3 scale) +{ + PIXEvent pixEvent(L"Skybox Render Simple Sky"); + + // Set the pixel shader constants + bool enableSun = sunSize > 0.0f && sunColor.x > 0.0f && sunColor.y > 0.0f && sunColor.z > 0.0f; + psConstantBuffer.Data.SkyColor = skyColor; + psConstantBuffer.Data.SunDirection = sunDirection; + psConstantBuffer.Data.EnableSun = enableSun ? 1 : 0; + psConstantBuffer.Data.SunColor = sunColor; + psConstantBuffer.Data.Scale = scale; + psConstantBuffer.Data.CosSunAngularRadius = std::cos(DegToRad(sunSize)); + + RenderCommon(context, nullptr, simpleSkyPS, view, projection, scale); +} + +Float3 Skybox::SampleSky(const SkyCache& cache, Float3 sampleDir) +{ + Assert_(cache.StateR != nullptr); + + float gamma = AngleBetween(sampleDir, cache.SunDirection); + float theta = AngleBetween(sampleDir, Float3(0, 1, 0)); + + Float3 radiance; + + radiance.x = float(arhosek_tristim_skymodel_radiance(cache.StateR, theta, gamma, 0)); + radiance.y = float(arhosek_tristim_skymodel_radiance(cache.StateG, theta, gamma, 1)); + radiance.z = float(arhosek_tristim_skymodel_radiance(cache.StateB, theta, gamma, 2)); + + // Multiply by standard luminous efficacy of 683 lm/W to bring us in line with the photometric + // units used during rendering + radiance *= 683.0f; + + radiance *= FP16Scale; + + return radiance; +} + +void Skybox::UpdateSkyCache(ID3D11Device* device, Float3 sunDirection, Float3 groundAlbedo, float turbidity) +{ + skyCache.Init(sunDirection, groundAlbedo, turbidity); + + if(skyCache.CubeMap == nullptr) + { + const uint64 CubeMapRes = 128; + std::vector texels; + texels.resize(CubeMapRes * CubeMapRes * 6); + + skyCache.SHProjection = SH9Color(); + float weightSum = 0.0f; + + for(uint64 s = 0; s < 6; ++s) + { + for(uint64 y = 0; y < CubeMapRes; ++y) + { + for(uint64 x = 0; x < CubeMapRes; ++x) + { + Float3 dir = MapXYSToDirection(x, y, s, CubeMapRes, CubeMapRes); + Float3 radiance = SampleSky(skyCache, dir); + + uint64 idx = (s * CubeMapRes * CubeMapRes) + (y * CubeMapRes) + x; + texels[idx] = Half4(Float4(radiance, 1.0f)); + + float u = (x + 0.5f) / CubeMapRes; + float v = (y + 0.5f) / CubeMapRes; + + // Account for cubemap texel distribution + u = u * 2.0f - 1.0f; + v = v * 2.0f - 1.0f; + const float temp = 1.0f + u * u + v * v; + const float weight = 4.0f / (sqrt(temp) * temp); + + skyCache.SHProjection += ProjectOntoSH9Color(dir, radiance) * weight; + weightSum += weight; + } + } + } + + skyCache.SHProjection *= (4.0f * 3.14159f) / weightSum; + + D3D11_TEXTURE2D_DESC desc; + desc.Width = uint32(CubeMapRes); + desc.Height = uint32(CubeMapRes); + desc.ArraySize = 6; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + desc.CPUAccessFlags = 0; + desc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; + desc.MipLevels = 1; + desc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_IMMUTABLE; + + D3D11_SUBRESOURCE_DATA resData[6]; + for(uint64 i = 0; i < 6; ++i) + { + resData[i].pSysMem = &texels[i * CubeMapRes * CubeMapRes]; + resData[i].SysMemPitch = sizeof(texels[0]) * CubeMapRes; + resData[i].SysMemSlicePitch = 0; + } + + ID3D11Texture2DPtr texture; + DXCall(device->CreateTexture2D(&desc, resData, &texture)); + DXCall(device->CreateShaderResourceView(texture, nullptr, &skyCache.CubeMap)); + } +} + +} diff --git a/SampleFramework11/v1.02/Graphics/Skybox.h b/SampleFramework11/v1.02/Graphics/Skybox.h index afb0401..9363490 100644 --- a/SampleFramework11/v1.02/Graphics/Skybox.h +++ b/SampleFramework11/v1.02/Graphics/Skybox.h @@ -1,124 +1,129 @@ -//================================================================================================= -// -// MJP's DX11 Sample Framework -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -#pragma once - -#include "..\\PCH.h" - -#include "..\\InterfacePointers.h" -#include "..\\SF11_Math.h" -#include "ShaderCompilation.h" -#include "GraphicsTypes.h" - -// HosekSky forward declares -struct ArHosekSkyModelState; - -namespace SampleFramework11 -{ - -// Cached data for the procedural sky model -struct SkyCache -{ - ArHosekSkyModelState* StateR = nullptr; - ArHosekSkyModelState* StateG = nullptr; - ArHosekSkyModelState* StateB = nullptr; - Float3 SunDirection; - float Turbidity = 0.0f; - Float3 Albedo; - float Elevation = 0.0f; - ID3D11ShaderResourceViewPtr CubeMap; - - void Init(Float3 sunDirection, Float3 groundAlbedo, float turbidity); - void Shutdown(); - ~SkyCache(); -}; - -class Skybox -{ - -public: - - Skybox(); - ~Skybox(); - - void Initialize(ID3D11Device* device); - - void RenderEnvironmentMap(ID3D11DeviceContext* context, - ID3D11ShaderResourceView* environmentMap, - const Float4x4& view, - const Float4x4& projection, - Float3 scale = Float3(1.0f, 1.0f, 1.0f)); - - void RenderSky(ID3D11DeviceContext* context, - Float3 sunDirection, - Float3 groundAlbedo, - Float3 sunColor, - float sunSize, - float turbidity, - const Float4x4& view, - const Float4x4& projection, - Float3 scale = Float3(1.0f, 1.0f, 1.0f)); - - void RenderSimpleSky(ID3D11DeviceContext* context, - Float3 skyColor, - Float3 sunDirection, - Float3 sunColor, - float sunSize, - const Float4x4& view, - const Float4x4& projection, - Float3 scake = Float3(1.0f, 1.0f, 1.0f)); - - static Float3 SampleSky(const SkyCache& cache, Float3 sampleDir); - -protected: - - void RenderCommon(ID3D11DeviceContext* context, - ID3D11ShaderResourceView* environmentMap, - ID3D11PixelShader* ps, - const Float4x4& view, - const Float4x4& projection, - Float3 scale); - - static const uint64 NumIndices = 36; - static const uint64 NumVertices = 8; - - struct VSConstants - { - Float4x4 View; - Float4x4 Projection; - }; - - struct PSConstants - { - Float3 SunDirection = Float3(0.0f, 1.0f, 0.0f); - bool32 EnableSun = false; - Float3 SkyColor = 1.0f; - Float4Align Float3 SunColor = 1.0f; - float CosSunAngularRadius = 0.0f; - Float3 Scale = 1.0f; - }; - - ID3D11DevicePtr device; - VertexShaderPtr vertexShader; - PixelShaderPtr emPixelShader; - PixelShaderPtr simpleSkyPS; - ID3D11InputLayoutPtr inputLayout; - ID3D11BufferPtr vertexBuffer; - ID3D11BufferPtr indexBuffer; - ConstantBuffer vsConstantBuffer; - ConstantBuffer psConstantBuffer; - ID3D11DepthStencilStatePtr dsState; - ID3D11BlendStatePtr blendState; - ID3D11RasterizerStatePtr rastState; - ID3D11SamplerStatePtr samplerState; - - SkyCache skyCache; -}; - +//================================================================================================= +// +// MJP's DX11 Sample Framework +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +#pragma once + +#include "..\\PCH.h" + +#include "..\\InterfacePointers.h" +#include "..\\SF11_Math.h" +#include "ShaderCompilation.h" +#include "GraphicsTypes.h" +#include "SH.h" + +// HosekSky forward declares +struct ArHosekSkyModelState; + +namespace SampleFramework11 +{ + +// Cached data for the procedural sky model +struct SkyCache +{ + ArHosekSkyModelState* StateR = nullptr; + ArHosekSkyModelState* StateG = nullptr; + ArHosekSkyModelState* StateB = nullptr; + Float3 SunDirection; + float Turbidity = 0.0f; + Float3 Albedo; + float Elevation = 0.0f; + ID3D11ShaderResourceViewPtr CubeMap; + SH9Color SHProjection; + + void Init(Float3 sunDirection, Float3 groundAlbedo, float turbidity); + void Shutdown(); + ~SkyCache(); +}; + +class Skybox +{ + +public: + + Skybox(); + ~Skybox(); + + void Initialize(ID3D11Device* device); + + void RenderEnvironmentMap(ID3D11DeviceContext* context, + ID3D11ShaderResourceView* environmentMap, + const Float4x4& view, + const Float4x4& projection, + Float3 scale = Float3(1.0f, 1.0f, 1.0f)); + + void RenderSky(ID3D11DeviceContext* context, + Float3 sunDirection, + Float3 groundAlbedo, + Float3 sunColor, + float sunSize, + float turbidity, + const Float4x4& view, + const Float4x4& projection, + Float3 scale = Float3(1.0f, 1.0f, 1.0f)); + + void RenderSimpleSky(ID3D11DeviceContext* context, + Float3 skyColor, + Float3 sunDirection, + Float3 sunColor, + float sunSize, + const Float4x4& view, + const Float4x4& projection, + Float3 scake = Float3(1.0f, 1.0f, 1.0f)); + + static Float3 SampleSky(const SkyCache& cache, Float3 sampleDir); + + const SkyCache& GetSkyCache() const { return skyCache; } + void UpdateSkyCache(ID3D11Device* device, Float3 sunDirection, Float3 groundAlbedo, float turbidity); + +protected: + + void RenderCommon(ID3D11DeviceContext* context, + ID3D11ShaderResourceView* environmentMap, + ID3D11PixelShader* ps, + const Float4x4& view, + const Float4x4& projection, + Float3 scale); + + static const uint64 NumIndices = 36; + static const uint64 NumVertices = 8; + + struct VSConstants + { + Float4x4 View; + Float4x4 Projection; + }; + + struct PSConstants + { + Float3 SunDirection = Float3(0.0f, 1.0f, 0.0f); + bool32 EnableSun = false; + Float3 SkyColor = 1.0f; + Float4Align Float3 SunColor = 1.0f; + float CosSunAngularRadius = 0.0f; + Float3 Scale = 1.0f; + }; + + ID3D11DevicePtr device; + VertexShaderPtr vertexShader; + PixelShaderPtr emPixelShader; + PixelShaderPtr simpleSkyPS; + ID3D11InputLayoutPtr inputLayout; + ID3D11BufferPtr vertexBuffer; + ID3D11BufferPtr indexBuffer; + ConstantBuffer vsConstantBuffer; + ConstantBuffer psConstantBuffer; + ID3D11DepthStencilStatePtr dsState; + ID3D11BlendStatePtr blendState; + ID3D11RasterizerStatePtr rastState; + ID3D11SamplerStatePtr samplerState; + + SkyCache skyCache; +}; + } \ No newline at end of file diff --git a/SampleFramework11/v1.02/Graphics/Textures.cpp b/SampleFramework11/v1.02/Graphics/Textures.cpp index 56dde8a..83ccf7c 100644 --- a/SampleFramework11/v1.02/Graphics/Textures.cpp +++ b/SampleFramework11/v1.02/Graphics/Textures.cpp @@ -1,363 +1,392 @@ -//================================================================================================= -// -// MJP's DX11 Sample Framework -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -#include "PCH.h" - -#include "..\\Utility.h" -#include "..\\Exceptions.h" -#include "Textures.h" -#include "DDSTextureLoader.h" -#include "WICTextureLoader.h" -#include "..\\FileIO.h" -#include "ShaderCompilation.h" -#include "GraphicsTypes.h" -#include "TinyEXR.h" - -namespace SampleFramework11 -{ - - // Loads a texture, using either the DDS loader or the WIC loader -ID3D11ShaderResourceViewPtr LoadTexture(ID3D11Device* device, const wchar* filePath, bool forceSRGB) -{ - ID3D11DeviceContextPtr context; - device->GetImmediateContext(&context); - - ID3D11ResourcePtr resource; - ID3D11ShaderResourceViewPtr srv; - - const std::wstring extension = GetFileExtension(filePath); - if(extension == L"DDS" || extension == L"dds") - { - DXCall(DirectX::CreateDDSTextureFromFileEx(device, filePath, 0, D3D11_USAGE_DEFAULT, - D3D11_BIND_SHADER_RESOURCE, 0, 0, forceSRGB, - &resource, &srv, nullptr)); - return srv; - } - else - { - DXCall(DirectX:: CreateWICTextureFromFileEx(device, context, filePath, 0, D3D11_USAGE_DEFAULT, - D3D11_BIND_SHADER_RESOURCE, 0, 0, forceSRGB, &resource, &srv)); - - return srv; - } -} - -template -static void GetTextureData(ID3D11Device* device, ID3D11ShaderResourceView* textureSRV, - DXGI_FORMAT outFormat, TextureData& texData) -{ - static ComputeShaderPtr decodeTextureCS; - static ComputeShaderPtr decodeTextureArrayCS; - - static const uint32 TGSize = 16; - - if(decodeTextureCS.Valid() == false) - { - CompileOptions opts; - opts.Add("TGSize_", TGSize); - const std::wstring shaderPath = SampleFrameworkDir() + L"Shaders\\DecodeTextureCS.hlsl"; - decodeTextureCS = CompileCSFromFile(device, shaderPath.c_str(), "DecodeTextureCS", "cs_5_0", opts); - - decodeTextureArrayCS = CompileCSFromFile(device, shaderPath.c_str(), "DecodeTextureArrayCS", "cs_5_0", opts); - } - - ID3D11Texture2DPtr texture; - textureSRV->GetResource(reinterpret_cast(&texture)); - - D3D11_TEXTURE2D_DESC texDesc; - texture->GetDesc(&texDesc); - - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - textureSRV->GetDesc(&srvDesc); - - ID3D11ShaderResourceViewPtr sourceSRV = textureSRV; - uint32 arraySize = texDesc.ArraySize; - if(srvDesc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURECUBE - || srvDesc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURECUBEARRAY) - { - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; - srvDesc.Texture2DArray.ArraySize = arraySize; - srvDesc.Texture2DArray.FirstArraySlice = 0; - srvDesc.Texture2DArray.MostDetailedMip = 0; - srvDesc.Texture2DArray.MipLevels = -1; - DXCall(device->CreateShaderResourceView(texture, &srvDesc, &sourceSRV)); - } - - D3D11_TEXTURE2D_DESC decodeTextureDesc; - decodeTextureDesc.Width = texDesc.Width; - decodeTextureDesc.Height = texDesc.Height; - decodeTextureDesc.ArraySize = arraySize; - decodeTextureDesc.BindFlags = D3D11_BIND_UNORDERED_ACCESS; - decodeTextureDesc.Format = outFormat; - decodeTextureDesc.MipLevels = 1; - decodeTextureDesc.MiscFlags = 0; - decodeTextureDesc.SampleDesc.Count = 1; - decodeTextureDesc.SampleDesc.Quality = 0; - decodeTextureDesc.Usage = D3D11_USAGE_DEFAULT; - decodeTextureDesc.CPUAccessFlags = 0; - - ID3D11Texture2DPtr decodeTexture; - DXCall(device->CreateTexture2D(&decodeTextureDesc, nullptr, &decodeTexture)); - - ID3D11UnorderedAccessViewPtr decodeTextureUAV; - DXCall(device->CreateUnorderedAccessView(decodeTexture, nullptr, &decodeTextureUAV)); - - ID3D11DeviceContextPtr context; - device->GetImmediateContext(&context); - - SetCSInputs(context, sourceSRV); - SetCSOutputs(context, decodeTextureUAV); - SetCSShader(context, arraySize > 1 ? decodeTextureArrayCS : decodeTextureCS); - - context->Dispatch(DispatchSize(TGSize, texDesc.Width), DispatchSize(TGSize, texDesc.Height), arraySize); - - ClearCSInputs(context); - ClearCSOutputs(context); - - StagingTexture2D stagingTexture; - stagingTexture.Initialize(device, texDesc.Width, texDesc.Height, outFormat, 1, 1, 0, arraySize); - context->CopyResource(stagingTexture.Texture, decodeTexture); - - texData.Init(texDesc.Width, texDesc.Height, arraySize); - - for(uint32 slice = 0; slice < arraySize; ++slice) - { - uint32 pitch = 0; - const uint8* srcData = reinterpret_cast(stagingTexture.Map(context, slice, pitch)); - Assert_(pitch >= texDesc.Width * sizeof(T)); - - const uint32 sliceOffset = texDesc.Width * texDesc.Height * slice; - - for(uint32 y = 0; y < texDesc.Height; ++y) - { - const T* rowData = reinterpret_cast(srcData); - - for(uint32 x = 0; x < texDesc.Width; ++x) - texData.Texels[y * texDesc.Width + x + sliceOffset] = rowData[x]; - - srcData += pitch; - } - } -} - -// Decode a texture into 32-bit floats and copies it to the CPU -void GetTextureData(ID3D11Device* device, ID3D11ShaderResourceView* textureSRV, - TextureData& textureData) -{ - GetTextureData(device, textureSRV, DXGI_FORMAT_R32G32B32A32_FLOAT, textureData); -} - -// Decode a texture into 16-bit floats and copies it to the CPU -void GetTextureData(ID3D11Device* device, ID3D11ShaderResourceView* textureSRV, - TextureData& textureData) -{ - GetTextureData(device, textureSRV, DXGI_FORMAT_R16G16B16A16_FLOAT, textureData); -} - -// Decode a texture into 32-bit floats and copies it to the CPU -void GetTextureData(ID3D11Device* device, ID3D11ShaderResourceView* textureSRV, - TextureData& textureData) -{ - GetTextureData(device, textureSRV, DXGI_FORMAT_R8G8B8A8_UNORM, textureData); -} - -template -static ID3D11ShaderResourceViewPtr CreateSRVFromTextureData(ID3D11Device* device, const TextureData& textureData) -{ - DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN; - if(typeid(T) == typeid(UByte4N)) - format = DXGI_FORMAT_R8G8B8A8_UNORM; - else if(typeid(T) == typeid(Half4)) - format = DXGI_FORMAT_R16G16B16A16_FLOAT; - else if(typeid(T) == typeid(Float4)) - format = DXGI_FORMAT_R32G32B32A32_FLOAT; - - Assert_(format != DXGI_FORMAT_UNKNOWN); - - const uint64 elemSize = sizeof(T); - Assert_(textureData.Texels.size() > 0); - Assert_(textureData.Width * textureData.Height * textureData.NumSlices == textureData.Texels.size()); - - std::vector subResources; - subResources.resize(textureData.NumSlices); - for(uint64 i = 0; i < textureData.NumSlices; ++i) - { - subResources[i].pSysMem = &textureData.Texels[textureData.Width * textureData.Height * i]; - subResources[i].SysMemPitch = elemSize * textureData.Width; - subResources[i].SysMemSlicePitch = 0; - } - - D3D11_TEXTURE2D_DESC texDesc; - texDesc.Width = textureData.Width; - texDesc.Height = textureData.Height; - texDesc.MipLevels = 1; - texDesc.ArraySize = textureData.NumSlices; - texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - texDesc.SampleDesc.Count = 1; - texDesc.SampleDesc.Quality = 0; - texDesc.Usage = D3D11_USAGE_IMMUTABLE; - texDesc.CPUAccessFlags = 0; - texDesc.MiscFlags = 0; - texDesc.Format = format; - ID3D11Texture2DPtr texture; - DXCall(device->CreateTexture2D(&texDesc, subResources.data(), &texture)); - - ID3D11ShaderResourceViewPtr srv; - DXCall(device->CreateShaderResourceView(texture, nullptr, &srv)); - - return srv; -} - -ID3D11ShaderResourceViewPtr CreateSRVFromTextureData(ID3D11Device* device, const TextureData& textureData) -{ - return CreateSRVFromTextureData(device, textureData); -} - -ID3D11ShaderResourceViewPtr CreateSRVFromTextureData(ID3D11Device* device, const TextureData& textureData) -{ - return CreateSRVFromTextureData(device, textureData); -} - -ID3D11ShaderResourceViewPtr CreateSRVFromTextureData(ID3D11Device* device, const TextureData& textureData) -{ - return CreateSRVFromTextureData(device, textureData); -} - -void SaveTextureAsDDS(ID3D11ShaderResourceView* srv, const wchar* filePath) -{ - ID3D11ResourcePtr texture; - srv->GetResource(&texture); - - SaveTextureAsDDS(texture, filePath); -} - -void SaveTextureAsDDS(ID3D11Resource* texture, const wchar* filePath) -{ - ID3D11DevicePtr device; - texture->GetDevice(&device); - - ID3D11DeviceContextPtr context; - device->GetImmediateContext(&context); - - ScratchImage scratchImage; - DXCall(CaptureTexture(device, context, texture, scratchImage)); - DXCall(SaveToDDSFile(scratchImage.GetImages(), scratchImage.GetImageCount(), - scratchImage.GetMetadata(), DDS_FLAGS_FORCE_DX10_EXT, filePath)); -} - -void SaveTextureAsEXR(ID3D11ShaderResourceView* srv, const wchar* filePath) -{ - ID3D11DevicePtr device; - srv->GetDevice(&device); - - TextureData textureData; - GetTextureData(device, srv, textureData); - - SaveTextureAsEXR(textureData, filePath); -} - -void SaveTextureAsEXR(const TextureData& texture, const wchar* filePath) -{ - Assert_(texture.Texels.size() > 0); - Assert_(texture.Width > 0 && texture.Height > 0); - Assert_(texture.NumSlices == 1); - - const uint64 numTexels = texture.Texels.size(); - std::vector channelDataR; - std::vector channelDataG; - std::vector channelDataB; - channelDataR.resize(numTexels); - channelDataG.resize(numTexels); - channelDataB.resize(numTexels); - for(uint64 i = 0; i < numTexels; ++i) - { - channelDataR[i] = texture.Texels[i].x; - channelDataG[i] = texture.Texels[i].y; - channelDataB[i] = texture.Texels[i].z; - } - - float* imageChannels[3] = { channelDataB.data(), channelDataG.data(), channelDataR.data() }; - const char* channelNames[3] = { "B", "G", "R" }; - - EXRImage exrImage; - exrImage.num_channels = 3; - exrImage.width = texture.Width; - exrImage.height = texture.Height; - exrImage.channel_names = channelNames; - exrImage.images = imageChannels; - - std::string filePathAnsi = WStringToAnsi(filePath); - - const char* errorString = nullptr; - int returnCode = SaveMultiChannelEXR(&exrImage, filePathAnsi.c_str(), &errorString); - if(returnCode != 0) - { - AssertFail_("%s", errorString); - throw Exception(AnsiToWString(errorString)); - } -} - -void SaveTextureAsPNG(ID3D11ShaderResourceView* srv, const wchar* filePath) -{ - ID3D11ResourcePtr texture; - srv->GetResource(&texture); - - SaveTextureAsPNG(texture, filePath); -} - -void SaveTextureAsPNG(ID3D11Resource* texture, const wchar* filePath) -{ - ID3D11DevicePtr device; - texture->GetDevice(&device); - - ID3D11DeviceContextPtr context; - device->GetImmediateContext(&context); - - ScratchImage scratchImage; - DXCall(CaptureTexture(device, context, texture, scratchImage)); - - DXCall(SaveToWICFile(scratchImage.GetImages(), scratchImage.GetImageCount(), WIC_FLAGS_NONE, - GetWICCodec(WIC_CODEC_PNG), filePath)); -} - -// Utility function to map a XY + Side coordinate to a direction vector -Float3 MapXYSToDirection(uint64 x, uint64 y, uint64 s, uint64 width, uint64 height) -{ - float u = ((x + 0.5f) / float(width)) * 2.0f - 1.0f; - float v = ((y + 0.5f) / float(height)) * 2.0f - 1.0f; - v *= -1.0f; - - Float3 dir = 0.0f; - - // +x, -x, +y, -y, +z, -z - switch(s) { - case 0: - dir = Float3::Normalize(Float3(1.0f, v, -u)); - break; - case 1: - dir = Float3::Normalize(Float3(-1.0f, v, u)); - break; - case 2: - dir = Float3::Normalize(Float3(u, 1.0f, -v)); - break; - case 3: - dir = Float3::Normalize(Float3(u, -1.0f, v)); - break; - case 4: - dir = Float3::Normalize(Float3(u, v, 1.0f)); - break; - case 5: - dir = Float3::Normalize(Float3(-u, v, -1.0f)); - break; - } - - return dir; -} - +//================================================================================================= +// +// MJP's DX11 Sample Framework +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +#include "PCH.h" + +#include "..\\Utility.h" +#include "..\\Exceptions.h" +#include "Textures.h" +#include "DDSTextureLoader.h" +#include "WICTextureLoader.h" +#include "..\\FileIO.h" +#include "ShaderCompilation.h" +#include "GraphicsTypes.h" +#include "TinyEXR.h" + +namespace SampleFramework11 +{ + +static const DXGI_FORMAT UnormFormats[] = +{ + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8_UNORM, + DXGI_FORMAT_R8_UNORM, + + DXGI_FORMAT_R16G16B16A16_UNORM, + DXGI_FORMAT_R16G16_UNORM, + DXGI_FORMAT_R16_UNORM, + + DXGI_FORMAT_R10G10B10A2_UNORM, +}; + +static bool IsUnormFormat(DXGI_FORMAT format) +{ + for(uint64 i = 0; i < ArraySize_(UnormFormats); ++i) + if(format == UnormFormats[i]) + return true; + return false; +} + +// Loads a texture, using either the DDS loader or the WIC loader +ID3D11ShaderResourceViewPtr LoadTexture(ID3D11Device* device, const wchar* filePath, bool forceSRGB) +{ + ID3D11DeviceContextPtr context; + device->GetImmediateContext(&context); + + ID3D11ResourcePtr resource; + ID3D11ShaderResourceViewPtr srv; + + const std::wstring extension = GetFileExtension(filePath); + if(extension == L"DDS" || extension == L"dds") + { + DXCall(DirectX::CreateDDSTextureFromFileEx(device, filePath, 0, D3D11_USAGE_DEFAULT, + D3D11_BIND_SHADER_RESOURCE, 0, 0, forceSRGB, + &resource, &srv, nullptr)); + return srv; + } + else + { + DXCall(DirectX:: CreateWICTextureFromFileEx(device, context, filePath, 0, D3D11_USAGE_DEFAULT, + D3D11_BIND_SHADER_RESOURCE, 0, 0, forceSRGB, &resource, &srv)); + + return srv; + } +} + +template +static void GetTextureData(ID3D11Device* device, ID3D11ShaderResourceView* textureSRV, + DXGI_FORMAT outFormat, TextureData& texData) +{ + static ComputeShaderPtr decodeTextureCS[2][2]; + static const uint32 TGSize = 16; + + if(decodeTextureCS[0][0].Valid() == false) + { + CompileOptions opts; + opts.Add("TGSize_", TGSize); + opts.Add("UnormOutput_", 0); + const std::wstring shaderPath = SampleFrameworkDir() + L"Shaders\\DecodeTextureCS.hlsl"; + + decodeTextureCS[0][0] = CompileCSFromFile(device, shaderPath.c_str(), "DecodeTextureCS", "cs_5_0", opts); + decodeTextureCS[0][1] = CompileCSFromFile(device, shaderPath.c_str(), "DecodeTextureArrayCS", "cs_5_0", opts); + + opts.Reset(); + opts.Add("TGSize_", TGSize); + opts.Add("UnormOutput_", 1); + decodeTextureCS[1][0] = CompileCSFromFile(device, shaderPath.c_str(), "DecodeTextureCS", "cs_5_0", opts); + decodeTextureCS[1][1] = CompileCSFromFile(device, shaderPath.c_str(), "DecodeTextureArrayCS", "cs_5_0", opts); + } + + ID3D11Texture2DPtr texture; + textureSRV->GetResource(reinterpret_cast(&texture)); + + D3D11_TEXTURE2D_DESC texDesc; + texture->GetDesc(&texDesc); + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + textureSRV->GetDesc(&srvDesc); + + ID3D11ShaderResourceViewPtr sourceSRV = textureSRV; + uint32 arraySize = texDesc.ArraySize; + if(srvDesc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURECUBE + || srvDesc.ViewDimension == D3D11_SRV_DIMENSION_TEXTURECUBEARRAY) + { + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + srvDesc.Texture2DArray.ArraySize = arraySize; + srvDesc.Texture2DArray.FirstArraySlice = 0; + srvDesc.Texture2DArray.MostDetailedMip = 0; + srvDesc.Texture2DArray.MipLevels = -1; + DXCall(device->CreateShaderResourceView(texture, &srvDesc, &sourceSRV)); + } + + D3D11_TEXTURE2D_DESC decodeTextureDesc; + decodeTextureDesc.Width = texDesc.Width; + decodeTextureDesc.Height = texDesc.Height; + decodeTextureDesc.ArraySize = arraySize; + decodeTextureDesc.BindFlags = D3D11_BIND_UNORDERED_ACCESS; + decodeTextureDesc.Format = outFormat; + decodeTextureDesc.MipLevels = 1; + decodeTextureDesc.MiscFlags = 0; + decodeTextureDesc.SampleDesc.Count = 1; + decodeTextureDesc.SampleDesc.Quality = 0; + decodeTextureDesc.Usage = D3D11_USAGE_DEFAULT; + decodeTextureDesc.CPUAccessFlags = 0; + + ID3D11Texture2DPtr decodeTexture; + DXCall(device->CreateTexture2D(&decodeTextureDesc, nullptr, &decodeTexture)); + + ID3D11UnorderedAccessViewPtr decodeTextureUAV; + DXCall(device->CreateUnorderedAccessView(decodeTexture, nullptr, &decodeTextureUAV)); + + ID3D11DeviceContextPtr context; + device->GetImmediateContext(&context); + + SetCSInputs(context, sourceSRV); + SetCSOutputs(context, decodeTextureUAV); + + uint32 arrayOutput = arraySize > 1 ? 1 : 0; + uint32 unormOutput = IsUnormFormat(outFormat) ? 1 : 0; + SetCSShader(context, decodeTextureCS[unormOutput][arrayOutput]); + + context->Dispatch(DispatchSize(TGSize, texDesc.Width), DispatchSize(TGSize, texDesc.Height), arraySize); + + ClearCSInputs(context); + ClearCSOutputs(context); + + StagingTexture2D stagingTexture; + stagingTexture.Initialize(device, texDesc.Width, texDesc.Height, outFormat, 1, 1, 0, arraySize); + context->CopyResource(stagingTexture.Texture, decodeTexture); + + texData.Init(texDesc.Width, texDesc.Height, arraySize); + + for(uint32 slice = 0; slice < arraySize; ++slice) + { + uint32 pitch = 0; + const uint8* srcData = reinterpret_cast(stagingTexture.Map(context, slice, pitch)); + Assert_(pitch >= texDesc.Width * sizeof(T)); + + const uint32 sliceOffset = texDesc.Width * texDesc.Height * slice; + + for(uint32 y = 0; y < texDesc.Height; ++y) + { + const T* rowData = reinterpret_cast(srcData); + + for(uint32 x = 0; x < texDesc.Width; ++x) + texData.Texels[y * texDesc.Width + x + sliceOffset] = rowData[x]; + + srcData += pitch; + } + } +} + +// Decode a texture into 32-bit floats and copies it to the CPU +void GetTextureData(ID3D11Device* device, ID3D11ShaderResourceView* textureSRV, + TextureData& textureData) +{ + GetTextureData(device, textureSRV, DXGI_FORMAT_R32G32B32A32_FLOAT, textureData); +} + +// Decode a texture into 16-bit floats and copies it to the CPU +void GetTextureData(ID3D11Device* device, ID3D11ShaderResourceView* textureSRV, + TextureData& textureData) +{ + GetTextureData(device, textureSRV, DXGI_FORMAT_R16G16B16A16_FLOAT, textureData); +} + +// Decode a texture into 32-bit floats and copies it to the CPU +void GetTextureData(ID3D11Device* device, ID3D11ShaderResourceView* textureSRV, + TextureData& textureData) +{ + GetTextureData(device, textureSRV, DXGI_FORMAT_R8G8B8A8_UNORM, textureData); +} + +template +static ID3D11ShaderResourceViewPtr CreateSRVFromTextureData(ID3D11Device* device, const TextureData& textureData) +{ + DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN; + if(typeid(T) == typeid(UByte4N)) + format = DXGI_FORMAT_R8G8B8A8_UNORM; + else if(typeid(T) == typeid(Half4)) + format = DXGI_FORMAT_R16G16B16A16_FLOAT; + else if(typeid(T) == typeid(Float4)) + format = DXGI_FORMAT_R32G32B32A32_FLOAT; + + Assert_(format != DXGI_FORMAT_UNKNOWN); + + const uint64 elemSize = sizeof(T); + Assert_(textureData.Texels.size() > 0); + Assert_(textureData.Width * textureData.Height * textureData.NumSlices == textureData.Texels.size()); + + std::vector subResources; + subResources.resize(textureData.NumSlices); + for(uint64 i = 0; i < textureData.NumSlices; ++i) + { + subResources[i].pSysMem = &textureData.Texels[textureData.Width * textureData.Height * i]; + subResources[i].SysMemPitch = elemSize * textureData.Width; + subResources[i].SysMemSlicePitch = 0; + } + + D3D11_TEXTURE2D_DESC texDesc; + texDesc.Width = textureData.Width; + texDesc.Height = textureData.Height; + texDesc.MipLevels = 1; + texDesc.ArraySize = textureData.NumSlices; + texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + texDesc.SampleDesc.Count = 1; + texDesc.SampleDesc.Quality = 0; + texDesc.Usage = D3D11_USAGE_IMMUTABLE; + texDesc.CPUAccessFlags = 0; + texDesc.MiscFlags = 0; + texDesc.Format = format; + ID3D11Texture2DPtr texture; + DXCall(device->CreateTexture2D(&texDesc, subResources.data(), &texture)); + + ID3D11ShaderResourceViewPtr srv; + DXCall(device->CreateShaderResourceView(texture, nullptr, &srv)); + + return srv; +} + +ID3D11ShaderResourceViewPtr CreateSRVFromTextureData(ID3D11Device* device, const TextureData& textureData) +{ + return CreateSRVFromTextureData(device, textureData); +} + +ID3D11ShaderResourceViewPtr CreateSRVFromTextureData(ID3D11Device* device, const TextureData& textureData) +{ + return CreateSRVFromTextureData(device, textureData); +} + +ID3D11ShaderResourceViewPtr CreateSRVFromTextureData(ID3D11Device* device, const TextureData& textureData) +{ + return CreateSRVFromTextureData(device, textureData); +} + +void SaveTextureAsDDS(ID3D11ShaderResourceView* srv, const wchar* filePath) +{ + ID3D11ResourcePtr texture; + srv->GetResource(&texture); + + SaveTextureAsDDS(texture, filePath); +} + +void SaveTextureAsDDS(ID3D11Resource* texture, const wchar* filePath) +{ + ID3D11DevicePtr device; + texture->GetDevice(&device); + + ID3D11DeviceContextPtr context; + device->GetImmediateContext(&context); + + ScratchImage scratchImage; + DXCall(CaptureTexture(device, context, texture, scratchImage)); + DXCall(SaveToDDSFile(scratchImage.GetImages(), scratchImage.GetImageCount(), + scratchImage.GetMetadata(), DDS_FLAGS_FORCE_DX10_EXT, filePath)); +} + +void SaveTextureAsEXR(ID3D11ShaderResourceView* srv, const wchar* filePath) +{ + ID3D11DevicePtr device; + srv->GetDevice(&device); + + TextureData textureData; + GetTextureData(device, srv, textureData); + + SaveTextureAsEXR(textureData, filePath); +} + +void SaveTextureAsEXR(const TextureData& texture, const wchar* filePath) +{ + Assert_(texture.Texels.size() > 0); + Assert_(texture.Width > 0 && texture.Height > 0); + Assert_(texture.NumSlices == 1); + + const uint64 numTexels = texture.Texels.size(); + std::vector channelDataR; + std::vector channelDataG; + std::vector channelDataB; + channelDataR.resize(numTexels); + channelDataG.resize(numTexels); + channelDataB.resize(numTexels); + for(uint64 i = 0; i < numTexels; ++i) + { + channelDataR[i] = texture.Texels[i].x; + channelDataG[i] = texture.Texels[i].y; + channelDataB[i] = texture.Texels[i].z; + } + + float* imageChannels[3] = { channelDataB.data(), channelDataG.data(), channelDataR.data() }; + const char* channelNames[3] = { "B", "G", "R" }; + + EXRImage exrImage; + exrImage.num_channels = 3; + exrImage.width = texture.Width; + exrImage.height = texture.Height; + exrImage.channel_names = channelNames; + exrImage.images = imageChannels; + + std::string filePathAnsi = WStringToAnsi(filePath); + + const char* errorString = nullptr; + int returnCode = SaveMultiChannelEXR(&exrImage, filePathAnsi.c_str(), &errorString); + if(returnCode != 0) + { + AssertFail_("%s", errorString); + throw Exception(AnsiToWString(errorString)); + } +} + +void SaveTextureAsPNG(ID3D11ShaderResourceView* srv, const wchar* filePath) +{ + ID3D11ResourcePtr texture; + srv->GetResource(&texture); + + SaveTextureAsPNG(texture, filePath); +} + +void SaveTextureAsPNG(ID3D11Resource* texture, const wchar* filePath) +{ + ID3D11DevicePtr device; + texture->GetDevice(&device); + + ID3D11DeviceContextPtr context; + device->GetImmediateContext(&context); + + ScratchImage scratchImage; + DXCall(CaptureTexture(device, context, texture, scratchImage)); + + DXCall(SaveToWICFile(scratchImage.GetImages(), scratchImage.GetImageCount(), WIC_FLAGS_NONE, + GetWICCodec(WIC_CODEC_PNG), filePath)); +} + +// Utility function to map a XY + Side coordinate to a direction vector +Float3 MapXYSToDirection(uint64 x, uint64 y, uint64 s, uint64 width, uint64 height) +{ + float u = ((x + 0.5f) / float(width)) * 2.0f - 1.0f; + float v = ((y + 0.5f) / float(height)) * 2.0f - 1.0f; + v *= -1.0f; + + Float3 dir = 0.0f; + + // +x, -x, +y, -y, +z, -z + switch(s) { + case 0: + dir = Float3::Normalize(Float3(1.0f, v, -u)); + break; + case 1: + dir = Float3::Normalize(Float3(-1.0f, v, u)); + break; + case 2: + dir = Float3::Normalize(Float3(u, 1.0f, -v)); + break; + case 3: + dir = Float3::Normalize(Float3(u, -1.0f, v)); + break; + case 4: + dir = Float3::Normalize(Float3(u, v, 1.0f)); + break; + case 5: + dir = Float3::Normalize(Float3(-u, v, -1.0f)); + break; + } + + return dir; +} + } \ No newline at end of file diff --git a/SampleFramework11/v1.02/InterfacePointers.h b/SampleFramework11/v1.02/InterfacePointers.h index 4df4895..c8ce374 100644 --- a/SampleFramework11/v1.02/InterfacePointers.h +++ b/SampleFramework11/v1.02/InterfacePointers.h @@ -1,83 +1,84 @@ -//================================================================================================= -// -// MJP's DX11 Sample Framework -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -#pragma once - -#include "PCH.h" - -namespace SampleFramework11 -{ - -// Device -_COM_SMARTPTR_TYPEDEF(ID3D11Device, __uuidof(ID3D11Device)); -_COM_SMARTPTR_TYPEDEF(ID3D11DeviceContext, __uuidof(ID3D11DeviceContext)); -_COM_SMARTPTR_TYPEDEF(ID3D11DeviceChild, __uuidof(ID3D11DeviceChild)); -_COM_SMARTPTR_TYPEDEF(ID3D11Query, __uuidof(ID3D11Query)); -_COM_SMARTPTR_TYPEDEF(ID3D11CommandList, __uuidof(ID3D11CommandList)); -_COM_SMARTPTR_TYPEDEF(ID3D11Counter, __uuidof(ID3D11Counter)); -_COM_SMARTPTR_TYPEDEF(ID3D11InputLayout, __uuidof(ID3D11InputLayout)); -_COM_SMARTPTR_TYPEDEF(ID3D11Predicate, __uuidof(ID3D11Predicate)); -_COM_SMARTPTR_TYPEDEF(ID3D11Asynchronous, __uuidof(ID3D11Asynchronous)); -_COM_SMARTPTR_TYPEDEF(ID3D11InfoQueue, __uuidof(ID3D11InfoQueue)); -_COM_SMARTPTR_TYPEDEF(ID3D11Debug, __uuidof(ID3D11Debug)); - -// States -_COM_SMARTPTR_TYPEDEF(ID3D11BlendState, __uuidof(ID3D11BlendState)); -_COM_SMARTPTR_TYPEDEF(ID3D11DepthStencilState, __uuidof(ID3D11DepthStencilState)); -_COM_SMARTPTR_TYPEDEF(ID3D11RasterizerState, __uuidof(ID3D11RasterizerState)); -_COM_SMARTPTR_TYPEDEF(ID3D11SamplerState, __uuidof(ID3D11SamplerState)); - -// Resources -_COM_SMARTPTR_TYPEDEF(ID3D11Resource, __uuidof(ID3D11Resource)); -_COM_SMARTPTR_TYPEDEF(ID3D11Texture1D, __uuidof(ID3D11Texture1D)); -_COM_SMARTPTR_TYPEDEF(ID3D11Texture2D, __uuidof(ID3D11Texture2D)); -_COM_SMARTPTR_TYPEDEF(ID3D11Texture3D, __uuidof(ID3D11Texture3D)); -_COM_SMARTPTR_TYPEDEF(ID3D11Buffer, __uuidof(ID3D11Buffer)); - -// Views -_COM_SMARTPTR_TYPEDEF(ID3D11View, __uuidof(ID3D11View)); -_COM_SMARTPTR_TYPEDEF(ID3D11RenderTargetView, __uuidof(ID3D11RenderTargetView)); -_COM_SMARTPTR_TYPEDEF(ID3D11ShaderResourceView, __uuidof(ID3D11ShaderResourceView)); -_COM_SMARTPTR_TYPEDEF(ID3D11DepthStencilView, __uuidof(ID3D11DepthStencilView)); -_COM_SMARTPTR_TYPEDEF(ID3D11UnorderedAccessView, __uuidof(ID3D11UnorderedAccessView)); - -// Shaders -_COM_SMARTPTR_TYPEDEF(ID3D11ComputeShader, __uuidof(ID3D11ComputeShader)); -_COM_SMARTPTR_TYPEDEF(ID3D11DomainShader, __uuidof(ID3D11DomainShader)); -_COM_SMARTPTR_TYPEDEF(ID3D11GeometryShader, __uuidof(ID3D11GeometryShader)); -_COM_SMARTPTR_TYPEDEF(ID3D11HullShader, __uuidof(ID3D11HullShader)); -_COM_SMARTPTR_TYPEDEF(ID3D11PixelShader, __uuidof(ID3D11PixelShader)); -_COM_SMARTPTR_TYPEDEF(ID3D11VertexShader, __uuidof(ID3D11VertexShader)); -_COM_SMARTPTR_TYPEDEF(ID3D11ClassInstance, __uuidof(ID3D11ClassInstance)); -_COM_SMARTPTR_TYPEDEF(ID3D11ClassLinkage, __uuidof(ID3D11ClassLinkage)); -_COM_SMARTPTR_TYPEDEF(ID3D11ShaderReflection, IID_ID3D11ShaderReflection); -_COM_SMARTPTR_TYPEDEF(ID3D11ShaderReflectionConstantBuffer, IID_ID3D11ShaderReflectionConstantBuffer); -_COM_SMARTPTR_TYPEDEF(ID3D11ShaderReflectionType, IID_ID3D11ShaderReflectionType); -_COM_SMARTPTR_TYPEDEF(ID3D11ShaderReflectionVariable, IID_ID3D11ShaderReflectionVariable); - -// D3D10 -_COM_SMARTPTR_TYPEDEF(ID3D10Blob, IID_ID3D10Blob); -typedef ID3D10BlobPtr ID3DBlobPtr; - -// DXGI -_COM_SMARTPTR_TYPEDEF(IDXGISwapChain, __uuidof(IDXGISwapChain)); -_COM_SMARTPTR_TYPEDEF(IDXGIAdapter, __uuidof(IDXGIAdapter)); -_COM_SMARTPTR_TYPEDEF(IDXGIAdapter1, __uuidof(IDXGIAdapter1)); -_COM_SMARTPTR_TYPEDEF(IDXGIDevice, __uuidof(IDXGIDevice)); -_COM_SMARTPTR_TYPEDEF(IDXGIDevice1, __uuidof(IDXGIDevice1)); -_COM_SMARTPTR_TYPEDEF(IDXGIDeviceSubObject, __uuidof(IDXGIDeviceSubObject)); -_COM_SMARTPTR_TYPEDEF(IDXGIFactory, __uuidof(IDXGIFactory)); -_COM_SMARTPTR_TYPEDEF(IDXGIFactory1, __uuidof(IDXGIFactory1)); -_COM_SMARTPTR_TYPEDEF(IDXGIKeyedMutex, __uuidof(IDXGIKeyedMutex)); -_COM_SMARTPTR_TYPEDEF(IDXGIObject, __uuidof(IDXGIObject)); -_COM_SMARTPTR_TYPEDEF(IDXGIOutput, __uuidof(IDXGIOutput)); -_COM_SMARTPTR_TYPEDEF(IDXGIResource, __uuidof(IDXGIResource)); -_COM_SMARTPTR_TYPEDEF(IDXGISurface1, __uuidof(IDXGISurface1)); - -} +//================================================================================================= +// +// MJP's DX11 Sample Framework +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +#pragma once + +#include "PCH.h" + +namespace SampleFramework11 +{ + +// Device +_COM_SMARTPTR_TYPEDEF(ID3D11Device, __uuidof(ID3D11Device)); +_COM_SMARTPTR_TYPEDEF(ID3D11DeviceContext, __uuidof(ID3D11DeviceContext)); +_COM_SMARTPTR_TYPEDEF(ID3D11DeviceChild, __uuidof(ID3D11DeviceChild)); +_COM_SMARTPTR_TYPEDEF(ID3D11Query, __uuidof(ID3D11Query)); +_COM_SMARTPTR_TYPEDEF(ID3D11CommandList, __uuidof(ID3D11CommandList)); +_COM_SMARTPTR_TYPEDEF(ID3D11Counter, __uuidof(ID3D11Counter)); +_COM_SMARTPTR_TYPEDEF(ID3D11InputLayout, __uuidof(ID3D11InputLayout)); +_COM_SMARTPTR_TYPEDEF(ID3D11Predicate, __uuidof(ID3D11Predicate)); +_COM_SMARTPTR_TYPEDEF(ID3D11Asynchronous, __uuidof(ID3D11Asynchronous)); +_COM_SMARTPTR_TYPEDEF(ID3D11InfoQueue, __uuidof(ID3D11InfoQueue)); +_COM_SMARTPTR_TYPEDEF(ID3D11Debug, __uuidof(ID3D11Debug)); + +// States +_COM_SMARTPTR_TYPEDEF(ID3D11BlendState, __uuidof(ID3D11BlendState)); +_COM_SMARTPTR_TYPEDEF(ID3D11DepthStencilState, __uuidof(ID3D11DepthStencilState)); +_COM_SMARTPTR_TYPEDEF(ID3D11RasterizerState, __uuidof(ID3D11RasterizerState)); +_COM_SMARTPTR_TYPEDEF(ID3D11RasterizerState2, __uuidof(ID3D11RasterizerState2)); +_COM_SMARTPTR_TYPEDEF(ID3D11SamplerState, __uuidof(ID3D11SamplerState)); + +// Resources +_COM_SMARTPTR_TYPEDEF(ID3D11Resource, __uuidof(ID3D11Resource)); +_COM_SMARTPTR_TYPEDEF(ID3D11Texture1D, __uuidof(ID3D11Texture1D)); +_COM_SMARTPTR_TYPEDEF(ID3D11Texture2D, __uuidof(ID3D11Texture2D)); +_COM_SMARTPTR_TYPEDEF(ID3D11Texture3D, __uuidof(ID3D11Texture3D)); +_COM_SMARTPTR_TYPEDEF(ID3D11Buffer, __uuidof(ID3D11Buffer)); + +// Views +_COM_SMARTPTR_TYPEDEF(ID3D11View, __uuidof(ID3D11View)); +_COM_SMARTPTR_TYPEDEF(ID3D11RenderTargetView, __uuidof(ID3D11RenderTargetView)); +_COM_SMARTPTR_TYPEDEF(ID3D11ShaderResourceView, __uuidof(ID3D11ShaderResourceView)); +_COM_SMARTPTR_TYPEDEF(ID3D11DepthStencilView, __uuidof(ID3D11DepthStencilView)); +_COM_SMARTPTR_TYPEDEF(ID3D11UnorderedAccessView, __uuidof(ID3D11UnorderedAccessView)); + +// Shaders +_COM_SMARTPTR_TYPEDEF(ID3D11ComputeShader, __uuidof(ID3D11ComputeShader)); +_COM_SMARTPTR_TYPEDEF(ID3D11DomainShader, __uuidof(ID3D11DomainShader)); +_COM_SMARTPTR_TYPEDEF(ID3D11GeometryShader, __uuidof(ID3D11GeometryShader)); +_COM_SMARTPTR_TYPEDEF(ID3D11HullShader, __uuidof(ID3D11HullShader)); +_COM_SMARTPTR_TYPEDEF(ID3D11PixelShader, __uuidof(ID3D11PixelShader)); +_COM_SMARTPTR_TYPEDEF(ID3D11VertexShader, __uuidof(ID3D11VertexShader)); +_COM_SMARTPTR_TYPEDEF(ID3D11ClassInstance, __uuidof(ID3D11ClassInstance)); +_COM_SMARTPTR_TYPEDEF(ID3D11ClassLinkage, __uuidof(ID3D11ClassLinkage)); +_COM_SMARTPTR_TYPEDEF(ID3D11ShaderReflection, IID_ID3D11ShaderReflection); +_COM_SMARTPTR_TYPEDEF(ID3D11ShaderReflectionConstantBuffer, IID_ID3D11ShaderReflectionConstantBuffer); +_COM_SMARTPTR_TYPEDEF(ID3D11ShaderReflectionType, IID_ID3D11ShaderReflectionType); +_COM_SMARTPTR_TYPEDEF(ID3D11ShaderReflectionVariable, IID_ID3D11ShaderReflectionVariable); + +// D3D10 +_COM_SMARTPTR_TYPEDEF(ID3D10Blob, IID_ID3D10Blob); +typedef ID3D10BlobPtr ID3DBlobPtr; + +// DXGI +_COM_SMARTPTR_TYPEDEF(IDXGISwapChain, __uuidof(IDXGISwapChain)); +_COM_SMARTPTR_TYPEDEF(IDXGIAdapter, __uuidof(IDXGIAdapter)); +_COM_SMARTPTR_TYPEDEF(IDXGIAdapter1, __uuidof(IDXGIAdapter1)); +_COM_SMARTPTR_TYPEDEF(IDXGIDevice, __uuidof(IDXGIDevice)); +_COM_SMARTPTR_TYPEDEF(IDXGIDevice1, __uuidof(IDXGIDevice1)); +_COM_SMARTPTR_TYPEDEF(IDXGIDeviceSubObject, __uuidof(IDXGIDeviceSubObject)); +_COM_SMARTPTR_TYPEDEF(IDXGIFactory, __uuidof(IDXGIFactory)); +_COM_SMARTPTR_TYPEDEF(IDXGIFactory1, __uuidof(IDXGIFactory1)); +_COM_SMARTPTR_TYPEDEF(IDXGIKeyedMutex, __uuidof(IDXGIKeyedMutex)); +_COM_SMARTPTR_TYPEDEF(IDXGIObject, __uuidof(IDXGIObject)); +_COM_SMARTPTR_TYPEDEF(IDXGIOutput, __uuidof(IDXGIOutput)); +_COM_SMARTPTR_TYPEDEF(IDXGIResource, __uuidof(IDXGIResource)); +_COM_SMARTPTR_TYPEDEF(IDXGISurface1, __uuidof(IDXGISurface1)); + +} diff --git a/SampleFramework11/v1.02/PCH.h b/SampleFramework11/v1.02/PCH.h index da90cf8..2d76725 100644 --- a/SampleFramework11/v1.02/PCH.h +++ b/SampleFramework11/v1.02/PCH.h @@ -1,179 +1,175 @@ -//================================================================================================= -// -// MJP's DX11 Sample Framework -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -#pragma once - -// Add common controls 6.0 DLL to the manifest -#if defined _M_IX86 -#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") -#elif defined _M_IA64 -#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"") -#elif defined _M_X64 -#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"") -#else -#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") -#endif - -// Standard int typedefs -#include -typedef int8_t int8; -typedef int16_t int16; -typedef int32_t int32; -typedef int64_t int64; -typedef uint8_t uint8; -typedef uint16_t uint16; -typedef uint32_t uint32; -typedef uint64_t uint64; - -typedef intptr_t intptr; -typedef uintptr_t uintptr; -typedef wchar_t wchar; -typedef uint32_t bool32; - -// Platform SDK defines, specifies that our min version is Windows Vista -#ifndef WINVER -#define WINVER 0x0600 -#endif - -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0600 -#endif - -#ifndef _WIN32_WINDOWS -#define _WIN32_WINDOWS 0x0410 -#endif - -#ifndef _WIN32_IE -#define _WIN32_IE 0x0700 -#endif - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -#define STRICT // Use strict declarations for Windows types - -// Windows Header Files: -#include -#include -#include -#include - -// MSVC COM Support -#include -#include - -// GDI+ -#include - -// DirectX Includes -#ifdef _DEBUG -#ifndef D3D_DEBUG_INFO -#define D3D_DEBUG_INFO -#endif -#endif - -#include -#include -#include -#include - -// DirectX Math -#include -#include -#include - -// DirectX Tex -#include "..\\..\\Externals\\DirectXTex Aug 2015\\Include\\DirectXTex.h" - -using namespace DirectX; -using namespace DirectX::PackedVector; - -// Un-define min and max from the windows headers -#ifdef min - #undef min -#endif - -#ifdef max - #undef max -#endif - -// C RunTime Header Files -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#pragma warning(push) -#pragma warning(disable : 4005) -#include -#pragma warning(pop) - -// C++ Standard Library Header Files -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// AntTweakBar -#include "..\\..\\Externals\\AntTweakBar\\include\\AntTweakBar.h" - -// Assimp -#include "..\\..\\Externals\\Assimp-3.1.1\\include\\Importer.hpp" -#include "..\\..\\Externals\\Assimp-3.1.1\\include\\scene.h" -#include "..\\..\\Externals\\Assimp-3.1.1\\include\\postprocess.h" - -// HosekSky lib -#include "..\\..\\Externals\\HosekSky\\Include\\ArHosekSkyModel.h" - -// Static Lib Imports -#pragma comment(lib, "dxguid.lib") -#pragma comment(lib, "D3D9.lib") -#pragma comment(lib, "D3D11.lib") -#pragma comment(lib, "DXGI.lib") -#pragma comment(lib, "comctl32.lib") -#pragma comment(lib, "psapi.lib") -#pragma comment(lib, "d3dcompiler.lib") -#pragma comment(lib, "gdiplus.lib") - -// Assimp -#pragma comment(lib, "assimp.lib") - -// AntTweakBar -#pragma comment(lib, "AntTweakBar64.lib") - -// DirectXTex -#pragma comment(lib, "DirectXTex.lib") - -// Hosek Sky -#ifdef _DEBUG - #pragma comment(lib, "HosekSky_Dbg.lib") -#else - #pragma comment(lib, "HosekSky.lib") -#endif - -#ifdef _DEBUG - #pragma comment(lib, "comsuppwd.lib") -#else - #pragma comment(lib, "comsuppw.lib") -#endif - +//================================================================================================= +// +// MJP's DX11 Sample Framework +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +#pragma once + +// Add common controls 6.0 DLL to the manifest +#if defined _M_IX86 +#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") +#elif defined _M_IA64 +#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"") +#elif defined _M_X64 +#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"") +#else +#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") +#endif + +// Standard int typedefs +#include +typedef int8_t int8; +typedef int16_t int16; +typedef int32_t int32; +typedef int64_t int64; +typedef uint8_t uint8; +typedef uint16_t uint16; +typedef uint32_t uint32; +typedef uint64_t uint64; + +typedef intptr_t intptr; +typedef uintptr_t uintptr; +typedef wchar_t wchar; +typedef uint32_t bool32; + +// Platform SDK defines, specifies that our min version is Windows Vista +#ifndef WINVER +#define WINVER 0x0600 +#endif + +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0600 +#endif + +#ifndef _WIN32_WINDOWS +#define _WIN32_WINDOWS 0x0410 +#endif + +#ifndef _WIN32_IE +#define _WIN32_IE 0x0700 +#endif + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define STRICT // Use strict declarations for Windows types + +// Windows Header Files: +#include +#include +#include +#include + +// MSVC COM Support +#include +#include + +// GDI+ +#include + +// DirectX Includes +#ifdef _DEBUG +#ifndef D3D_DEBUG_INFO +#define D3D_DEBUG_INFO +#endif +#endif + +#include +#include +#include +#include +#include +#include +#include + +// DirectX Math +#include +#include +#include + +// DirectX Tex +#include "..\\..\\Externals\\DirectXTex Aug 2015\\Include\\DirectXTex.h" + +using namespace DirectX; +using namespace DirectX::PackedVector; + +// Un-define min and max from the windows headers +#ifdef min + #undef min +#endif + +#ifdef max + #undef max +#endif + +// C RunTime Header Files +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma warning(push) +#pragma warning(disable : 4005) +#include +#pragma warning(pop) + +// C++ Standard Library Header Files +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// AntTweakBar +#include "..\\..\\Externals\\AntTweakBar\\include\\AntTweakBar.h" + +// Assimp +#include "..\\..\\Externals\\Assimp-3.1.1\\include\\Importer.hpp" +#include "..\\..\\Externals\\Assimp-3.1.1\\include\\scene.h" +#include "..\\..\\Externals\\Assimp-3.1.1\\include\\postprocess.h" + +// HosekSky lib +#include "..\\..\\Externals\\HosekSky\\Include\\ArHosekSkyModel.h" + +// Static Lib Imports +#pragma comment(lib, "dxguid.lib") +#pragma comment(lib, "D3D9.lib") +#pragma comment(lib, "D3D11.lib") +#pragma comment(lib, "DXGI.lib") +#pragma comment(lib, "comctl32.lib") +#pragma comment(lib, "psapi.lib") +#pragma comment(lib, "d3dcompiler.lib") +#pragma comment(lib, "gdiplus.lib") + +// Assimp +#pragma comment(lib, "assimp.lib") + +// AntTweakBar +#pragma comment(lib, "AntTweakBar64.lib") + +// DirectXTex +#pragma comment(lib, "DirectXTex.lib") + +#ifdef _DEBUG + #pragma comment(lib, "comsuppwd.lib") +#else + #pragma comment(lib, "comsuppw.lib") +#endif + #include \ No newline at end of file diff --git a/SampleFramework11/v1.02/Shaders/DecodeTextureCS.hlsl b/SampleFramework11/v1.02/Shaders/DecodeTextureCS.hlsl index 8f0f35c..325ec82 100644 --- a/SampleFramework11/v1.02/Shaders/DecodeTextureCS.hlsl +++ b/SampleFramework11/v1.02/Shaders/DecodeTextureCS.hlsl @@ -1,37 +1,42 @@ -//================================================================================================= -// -// MJP's DX11 Sample Framework -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -//================================================================================================= -// Resources -//================================================================================================= - -// Inputs -Texture2D InputTexture : register(t0); -Texture2DArray InputTextureArray : register(t0); - -// Outputs -RWTexture2D OutputTexture : register(u0); -RWTexture2DArray OutputTextureArray : register(u0); - -//================================================================================================= -// Entry points -//================================================================================================= -[numthreads(TGSize_, TGSize_, 1)] -void DecodeTextureCS(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : SV_GroupThreadID) -{ - const uint2 texelIdx = GroupID.xy * uint2(TGSize_, TGSize_) + GroupThreadID.xy; - OutputTexture[texelIdx] = InputTexture[texelIdx]; -} - -[numthreads(TGSize_, TGSize_, 1)] -void DecodeTextureArrayCS(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : SV_GroupThreadID) -{ - const uint3 texelIdx = uint3(GroupID.xy * uint2(TGSize_, TGSize_) + GroupThreadID.xy, GroupID.z); - OutputTextureArray[texelIdx] = InputTextureArray[texelIdx]; +//================================================================================================= +// +// MJP's DX11 Sample Framework +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +//================================================================================================= +// Resources +//================================================================================================= + +// Inputs +Texture2D InputTexture : register(t0); +Texture2DArray InputTextureArray : register(t0); + +// Outputs +#if UnormOutput_ + RWTexture2D OutputTexture : register(u0); + RWTexture2DArray OutputTextureArray : register(u0); +#else + RWTexture2D OutputTexture : register(u0); + RWTexture2DArray OutputTextureArray : register(u0); +#endif + +//================================================================================================= +// Entry points +//================================================================================================= +[numthreads(TGSize_, TGSize_, 1)] +void DecodeTextureCS(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : SV_GroupThreadID) +{ + const uint2 texelIdx = GroupID.xy * uint2(TGSize_, TGSize_) + GroupThreadID.xy; + OutputTexture[texelIdx] = InputTexture[texelIdx]; +} + +[numthreads(TGSize_, TGSize_, 1)] +void DecodeTextureArrayCS(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : SV_GroupThreadID) +{ + const uint3 texelIdx = uint3(GroupID.xy * uint2(TGSize_, TGSize_) + GroupThreadID.xy, GroupID.z); + OutputTextureArray[texelIdx] = InputTextureArray[texelIdx]; } \ No newline at end of file diff --git a/SampleFramework11/v1.02/Shaders/Quaternion.hlsl b/SampleFramework11/v1.02/Shaders/Quaternion.hlsl new file mode 100644 index 0000000..ec149ed --- /dev/null +++ b/SampleFramework11/v1.02/Shaders/Quaternion.hlsl @@ -0,0 +1,149 @@ +//================================================================================================= +// +// MJP's DX12 Sample Framework +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +#ifndef QAUTERNION_HLSL_ +#define QAUTERNION_HLSL_ + +typedef float4 Quaternion; + +float3 QuatRotate(in float3 v, in Quaternion q) +{ + float3 t = 2 * cross(q.xyz, v); + return v + q.w * t + cross(q.xyz, t); +} + +Quaternion QuatFrom3x3(in float3x3 m) +{ + float3x3 a = transpose(m); + Quaternion q; + float trace = a[0][0] + a[1][1] + a[2][2]; + if(trace > 0) + { + float s = 0.5f / sqrt(trace + 1.0f); + q.w = 0.25f / s; + q.x = (a[2][1] - a[1][2]) * s; + q.y = (a[0][2] - a[2][0]) * s; + q.z = (a[1][0] - a[0][1]) * s; + } + else + { + if(a[0][0] > a[1][1] && a[0][0] > a[2][2]) + { + float s = 2.0f * sqrt(1.0f + a[0][0] - a[1][1] - a[2][2]); + q.w = (a[2][1] - a[1][2]) / s; + q.x = 0.25f * s; + q.y = (a[0][1] + a[1][0]) / s; + q.z = (a[0][2] + a[2][0]) / s; + } + else if(a[1][1] > a[2][2]) + { + float s = 2.0f * sqrt(1.0f + a[1][1] - a[0][0] - a[2][2]); + q.w = (a[0][2] - a[2][0]) / s; + q.x = (a[0][1] + a[1][0]) / s; + q.y = 0.25f * s; + q.z = (a[1][2] + a[2][1]) / s; + } + else + { + float s = 2.0f * sqrt(1.0f + a[2][2] - a[0][0] - a[1][1]); + q.w = (a[1][0] - a[0][1]) / s; + q.x = (a[0][2] + a[2][0]) / s; + q.y = (a[1][2] + a[2][1]) / s; + q.z = 0.25f * s; + } + } + return q; +} + +float3x3 QuatTo3x3(in Quaternion q) +{ + float3x3 m = float3x3(1.0f - 2.0f * q.y * q.y - 2.0f * q.z * q.z, 2.0f * q.x * q.y - 2.0f * q.z * q.w, 2.0f * q.x * q.z + 2.0f * q.y * q.w, + 2.0f * q.x * q.y + 2.0f * q.z * q.w, 1.0f - 2.0f * q.x * q.x - 2.0f * q.z * q.z, 2.0f * q.y * q.z - 2.0f * q.x * q.w, + 2.0f * q.x * q.z - 2.0f * q.y * q.w, 2.0f * q.y * q.z + 2.0f * q.x * q.w, 1.0f - 2.0f * q.x * q.x - 2.0f * q.y * q.y); + return transpose(m); +} + +float4x4 QuatTo4x4(in Quaternion q) +{ + float3x3 m3x3 = QuatTo3x3(q); + return float4x4(m3x3._m00, m3x3._m01, m3x3._m02, 0.0f, + m3x3._m10, m3x3._m11, m3x3._m12, 0.0f, + m3x3._m20, m3x3._m21, m3x3._m22, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f); +} + +float4 PackQuaternion(in Quaternion q) +{ + Quaternion absQ = abs(q); + float absMaxComponent = max(max(absQ.x, absQ.y), max(absQ.z, absQ.w)); + + uint maxCompIdx = 0; + float maxComponent = q.x; + + [unroll] + for(uint i = 0; i < 4; ++i) + { + if(absQ[i] == absMaxComponent) + { + maxCompIdx = i; + maxComponent = q[i]; + } + } + + if(maxComponent < 0.0f) + q *= -1.0f; + + float3 components; + if(maxCompIdx == 0) + components = q.yzw; + else if(maxCompIdx == 1) + components = q.xzw; + else if(maxCompIdx == 2) + components = q.xyw; + else + components = q.xyz; + + const float maxRange = 1.0f / sqrt(2.0f); + components /= maxRange; + components = components * 0.5f + 0.5f; + + return float4(components, maxCompIdx / 3.0f); +} + +Quaternion UnpackQuaternion(in float4 packed) +{ + uint maxCompIdx = uint(packed.w * 3.0f); + packed.xyz = packed.xyz * 2.0f - 1.0f; + const float maxRange = 1.0f / sqrt(2.0f); + packed.xyz *= maxRange; + float maxComponent = sqrt(1.0f - saturate(packed.x * packed.x + packed.y * packed.y + packed.z * packed.z)); + + Quaternion q; + if(maxCompIdx == 0) + q = Quaternion(maxComponent, packed.xyz); + else if(maxCompIdx == 1) + q = Quaternion(packed.x, maxComponent, packed.yz); + else if(maxCompIdx == 2) + q = Quaternion(packed.xy, maxComponent, packed.z); + else + q = Quaternion(packed.xyz, maxComponent); + + return q; +} + +Quaternion ShortestArcRotation(in float3 v1, in float3 v2) +{ + Quaternion q; + q.xyz = cross(v1, v2); + q.w = dot(v1, v2); + + return q; +} + +#endif // QAUTERNION_HLSL_ \ No newline at end of file diff --git a/SampleFramework11/v1.02/Shaders/SH.hlsl b/SampleFramework11/v1.02/Shaders/SH.hlsl index 77c87f8..4cc1bdf 100644 --- a/SampleFramework11/v1.02/Shaders/SH.hlsl +++ b/SampleFramework11/v1.02/Shaders/SH.hlsl @@ -11,22 +11,22 @@ struct SH4 { - float c[4]; + float c[4]; }; struct SH4Color { - float3 c[4]; + float3 c[4]; }; struct SH9 { - float c[9]; + float c[9]; }; struct SH9Color { - float3 c[9]; + float3 c[9]; }; typedef float4 H4; @@ -64,9 +64,9 @@ SH4 ProjectOntoSH4(in float3 dir, in float intensity, in float A0, in float A1) sh.c[0] = 0.282095f * A0 * intensity; // Band 1 - sh.c[1] = 0.488603f * dir.y * A1 * intensity; + sh.c[1] = -0.488603f * dir.y * A1 * intensity; sh.c[2] = 0.488603f * dir.z * A1 * intensity; - sh.c[3] = 0.488603f * dir.x * A1 * intensity; + sh.c[3] = -0.488603f * dir.x * A1 * intensity; return sh; } @@ -79,9 +79,9 @@ SH4Color ProjectOntoSH4Color(in float3 dir, in float3 color, in float A0, in flo sh.c[0] = 0.282095f * A0 * color; // Band 1 - sh.c[1] = 0.488603f * dir.y * A1 * color; + sh.c[1] = -0.488603f * dir.y * A1 * color; sh.c[2] = 0.488603f * dir.z * A1 * color; - sh.c[3] = 0.488603f * dir.x * A1 * color; + sh.c[3] = -0.488603f * dir.x * A1 * color; return sh; } @@ -112,46 +112,46 @@ SH4Color ProjectOntoSH4Color(in float3 dir) //------------------------------------------------------------------------------------------------- float SHDotProduct(in SH4 a, in SH4 b) { - float result = 0.0f; + float result = 0.0f; - [unroll] - for(uint i = 0; i < 4; ++i) - result += a.c[i] * b.c[i]; + [unroll] + for(uint i = 0; i < 4; ++i) + result += a.c[i] * b.c[i]; - return result; + return result; } float3 SHDotProduct(in SH4 a, in SH4Color b) { - float3 result = 0.0f; + float3 result = 0.0f; - [unroll] - for(uint i = 0; i < 4; ++i) - result += a.c[i] * b.c[i]; + [unroll] + for(uint i = 0; i < 4; ++i) + result += a.c[i] * b.c[i]; - return result; + return result; } float3 SHDotProduct(in SH4Color a, in SH4 b) { - float3 result = 0.0f; + float3 result = 0.0f; - [unroll] - for(uint i = 0; i < 4; ++i) - result += a.c[i] * b.c[i]; + [unroll] + for(uint i = 0; i < 4; ++i) + result += a.c[i] * b.c[i]; - return result; + return result; } float3 SHDotProduct(in SH4Color a, in SH4Color b) { - float3 result = 0.0f; + float3 result = 0.0f; - [unroll] - for(uint i = 0; i < 4; ++i) - result += a.c[i] * b.c[i]; + [unroll] + for(uint i = 0; i < 4; ++i) + result += a.c[i] * b.c[i]; - return result; + return result; } //------------------------------------------------------------------------------------------------- @@ -159,14 +159,14 @@ float3 SHDotProduct(in SH4Color a, in SH4Color b) //------------------------------------------------------------------------------------------------- float3 EvalSH4(in float3 dir, in SH4 sh) { - SH4 dirSH = ProjectOntoSH4(dir); - return SHDotProduct(dirSH, sh); + SH4 dirSH = ProjectOntoSH4(dir); + return SHDotProduct(dirSH, sh); } float3 EvalSH4(in float3 dir, in SH4Color sh) { - SH4Color dirSH = ProjectOntoSH4Color(dir, 1.0f); - return SHDotProduct(dirSH, sh); + SH4Color dirSH = ProjectOntoSH4Color(dir, 1.0f); + return SHDotProduct(dirSH, sh); } //------------------------------------------------------------------------------------------------- @@ -175,14 +175,14 @@ float3 EvalSH4(in float3 dir, in SH4Color sh) //------------------------------------------------------------------------------------------------- float EvalSH4Irradiance(in float3 dir, in SH4 sh) { - SH4 dirSH = ProjectOntoSH4(dir, 1.0f, CosineA0, CosineA1); - return SHDotProduct(dirSH, sh); + SH4 dirSH = ProjectOntoSH4(dir, 1.0f, CosineA0, CosineA1); + return SHDotProduct(dirSH, sh); } float3 EvalSH4Irradiance(in float3 dir, in SH4Color sh) { - SH4Color dirSH = ProjectOntoSH4Color(dir, 1.0f, CosineA0, CosineA1); - return SHDotProduct(dirSH, sh); + SH4Color dirSH = ProjectOntoSH4Color(dir, 1.0f, CosineA0, CosineA1); + return SHDotProduct(dirSH, sh); } //------------------------------------------------------------------------------------------------- @@ -245,14 +245,14 @@ SH4 RotateSH4(in SH4 sh, in float3x3 rotation) { const float r00 = rotation._m00; const float r10 = rotation._m01; - const float r20 = -rotation._m02; + const float r20 = rotation._m02; const float r01 = rotation._m10; const float r11 = rotation._m11; - const float r21 = -rotation._m12; + const float r21 = rotation._m12; - const float r02 = -rotation._m20; - const float r12 = -rotation._m21; + const float r02 = rotation._m20; + const float r12 = rotation._m21; const float r22 = rotation._m22; SH4 result; @@ -272,14 +272,14 @@ SH4Color RotateSH4(in SH4Color sh, in float3x3 rotation) { const float r00 = rotation._m00; const float r10 = rotation._m01; - const float r20 = -rotation._m02; + const float r20 = rotation._m02; const float r01 = rotation._m10; const float r11 = rotation._m11; - const float r21 = -rotation._m12; + const float r21 = rotation._m12; - const float r02 = -rotation._m20; - const float r12 = -rotation._m21; + const float r02 = rotation._m20; + const float r12 = rotation._m21; const float r22 = rotation._m22; SH4Color result; @@ -308,15 +308,15 @@ SH9 ProjectOntoSH9(in float3 n, in float intensity, in float A0, in float A1, in sh.c[0] = 0.282095f * A0 * intensity; // Band 1 - sh.c[1] = 0.488603f * n.y * A1 * intensity; + sh.c[1] = -0.488603f * n.y * A1 * intensity; sh.c[2] = 0.488603f * n.z * A1 * intensity; - sh.c[3] = 0.488603f * n.x * A1 * intensity; + sh.c[3] = -0.488603f * n.x * A1 * intensity; // Band 2 sh.c[4] = 1.092548f * n.x * n.y * A2 * intensity; - sh.c[5] = 1.092548f * n.y * n.z * A2 * intensity; + sh.c[5] = -1.092548f * n.y * n.z * A2 * intensity; sh.c[6] = 0.315392f * (3.0f * n.z * n.z - 1.0f) * A2 * intensity; - sh.c[7] = 1.092548f * n.x * n.z * A2 * intensity; + sh.c[7] = -1.092548f * n.x * n.z * A2 * intensity; sh.c[8] = 0.546274f * (n.x * n.x - n.y * n.y) * A2 * intensity; return sh; @@ -330,15 +330,15 @@ SH9Color ProjectOntoSH9Color(in float3 n, in float3 color, in float A0, in float sh.c[0] = 0.282095f * A0 * color; // Band 1 - sh.c[1] = 0.488603f * n.y * A1 * color; + sh.c[1] = -0.488603f * n.y * A1 * color; sh.c[2] = 0.488603f * n.z * A1 * color; - sh.c[3] = 0.488603f * n.x * A1 * color; + sh.c[3] = -0.488603f * n.x * A1 * color; // Band 2 sh.c[4] = 1.092548f * n.x * n.y * A2 * color; - sh.c[5] = 1.092548f * n.y * n.z * A2 * color; + sh.c[5] = -1.092548f * n.y * n.z * A2 * color; sh.c[6] = 0.315392f * (3.0f * n.z * n.z - 1.0f) * A2 * color; - sh.c[7] = 1.092548f * n.x * n.z * A2 * color; + sh.c[7] = -1.092548f * n.x * n.z * A2 * color; sh.c[8] = 0.546274f * (n.x * n.x - n.y * n.y) * A2 * color; return sh; @@ -346,22 +346,22 @@ SH9Color ProjectOntoSH9Color(in float3 n, in float3 color, in float A0, in float SH9 ProjectOntoSH9(in float3 dir, in float intensity) { - return ProjectOntoSH9(dir, intensity, 1.0f, 1.0f, 1.0f); + return ProjectOntoSH9(dir, intensity, 1.0f, 1.0f, 1.0f); } SH9Color ProjectOntoSH9Color(in float3 dir, in float3 color) { - return ProjectOntoSH9Color(dir, color, 1.0f, 1.0f, 1.0f); + return ProjectOntoSH9Color(dir, color, 1.0f, 1.0f, 1.0f); } SH9 ProjectOntoSH9(in float3 dir) { - return ProjectOntoSH9(dir, 1.0f, 1.0f, 1.0f, 1.0f); + return ProjectOntoSH9(dir, 1.0f, 1.0f, 1.0f, 1.0f); } SH9Color ProjectOntoSH9Color(in float3 dir) { - return ProjectOntoSH9Color(dir, 1.0f, 1.0f, 1.0f, 1.0f); + return ProjectOntoSH9Color(dir, 1.0f, 1.0f, 1.0f, 1.0f); } //------------------------------------------------------------------------------------------------- @@ -369,48 +369,48 @@ SH9Color ProjectOntoSH9Color(in float3 dir) //------------------------------------------------------------------------------------------------- float SHDotProduct(in SH9 a, in SH9 b) { - float result = 0.0f; + float result = 0.0f; - [unroll] - for(uint i = 0; i < 9; ++i) - result += a.c[i] * b.c[i]; + [unroll] + for(uint i = 0; i < 9; ++i) + result += a.c[i] * b.c[i]; - return result; + return result; } float3 SHDotProduct(in SH9Color a, in SH9 b) { - float3 result = 0.0f; + float3 result = 0.0f; - [unroll] - for(uint i = 0; i < 9; ++i) - result += a.c[i] * b.c[i]; + [unroll] + for(uint i = 0; i < 9; ++i) + result += a.c[i] * b.c[i]; - return result; + return result; } float3 SHDotProduct(in SH9 a, in SH9Color b) { - float3 result = 0.0f; + float3 result = 0.0f; - [unroll] - for(uint i = 0; i < 9; ++i) - result += a.c[i] * b.c[i]; + [unroll] + for(uint i = 0; i < 9; ++i) + result += a.c[i] * b.c[i]; - return result; + return result; } float3 SHDotProduct(in SH9Color a, in SH9Color b) { - float3 result = 0.0f; + float3 result = 0.0f; - [unroll] - for(uint i = 0; i < 9; ++i) - result += a.c[i] * b.c[i]; + [unroll] + for(uint i = 0; i < 9; ++i) + result += a.c[i] * b.c[i]; - return result; + return result; } //------------------------------------------------------------------------------------------------- @@ -418,14 +418,14 @@ float3 SHDotProduct(in SH9Color a, in SH9Color b) //------------------------------------------------------------------------------------------------- float EvalSH9(in float3 dir, in SH9 sh) { - SH9 dirSH = ProjectOntoSH9(dir); - return SHDotProduct(dirSH, sh); + SH9 dirSH = ProjectOntoSH9(dir); + return SHDotProduct(dirSH, sh); } float3 EvalSH9(in float3 dir, in SH9Color sh) { - SH9Color dirSH = ProjectOntoSH9Color(dir); - return SHDotProduct(dirSH, sh); + SH9Color dirSH = ProjectOntoSH9Color(dir); + return SHDotProduct(dirSH, sh); } //------------------------------------------------------------------------------------------------- @@ -434,14 +434,14 @@ float3 EvalSH9(in float3 dir, in SH9Color sh) //------------------------------------------------------------------------------------------------- float EvalSH9Irradiance(in float3 dir, in SH9 sh) { - SH9 dirSH = ProjectOntoSH9(dir, 1.0f, CosineA0, CosineA1, CosineA2); - return SHDotProduct(dirSH, sh); + SH9 dirSH = ProjectOntoSH9(dir, 1.0f, CosineA0, CosineA1, CosineA2); + return SHDotProduct(dirSH, sh); } float3 EvalSH9Irradiance(in float3 dir, in SH9Color sh) { - SH9Color dirSH = ProjectOntoSH9Color(dir, 1.0f, CosineA0, CosineA1, CosineA2); - return SHDotProduct(dirSH, sh); + SH9Color dirSH = ProjectOntoSH9Color(dir, 1.0f, CosineA0, CosineA1, CosineA2); + return SHDotProduct(dirSH, sh); } //------------------------------------------------------------------------------------------------- @@ -516,14 +516,14 @@ SH9 RotateSH9(in SH9 sh, in float3x3 rotation) { const float r00 = rotation._m00; const float r10 = rotation._m01; - const float r20 = -rotation._m02; + const float r20 = rotation._m02; const float r01 = rotation._m10; const float r11 = rotation._m11; - const float r21 = -rotation._m12; + const float r21 = rotation._m12; - const float r02 = -rotation._m20; - const float r12 = -rotation._m21; + const float r02 = rotation._m20; + const float r12 = rotation._m21; const float r22 = rotation._m22; SH9 result; @@ -562,29 +562,29 @@ SH9 RotateSH9(in SH9 sh, in float3x3 rotation) float r[25]; r[0] = r11 * r00 + r01 * r10; r[1] = -r01 * r12 - r11 * r02; - r[2] = v173 * r02 * r12; + r[2] = v173 * r02 * r12; r[3] = -r10 * r02 - r00 * r12; r[4] = r00 * r10 - r01 * r11; - r[5] = - r11 * r20 - r21 * r10; + r[5] = -r11 * r20 - r21 * r10; r[6] = r11 * r22 + r21 * r12; r[7] = -v173 * r22 * r12; r[8] = r20 * r12 + r10 * r22; r[9] = -r10 * r20 + r11 * r21; - r[10] = -v577 * (t41 + t43) + v115 * r21 * r20; - r[11] = v577 * (t48 + t50) - v115 * r21 * r22; - r[12] = -0.5000000000e0f * (t55 + t58) + t57; + r[10] = -v577* (t41 + t43) + v115 * r21 * r20; + r[11] = v577* (t48 + t50) - v115 * r21 * r22; + r[12] = -0.5f * (t55 + t58) + t57; r[13] = v577 * (t61 + t63) - v115 * r20 * r22; - r[14] = v288 * (t70 - t68 + t72 - t74) - v577 * (t76 - t78); - r[15] = -r01 * r20 - r21 * r00; + r[14] = v288 * (t70 - t68 + t72 - t74) - v577 * (t76 - t78); + r[15] = -r01 * r20 - r21 * r00; r[16] = r01 * r22 + r21 * r02; r[17] = -v173 * r22 * r02; r[18] = r00 * r22 + r20 * r02; r[19] = -r00 * r20 + r01 * r21; r[20] = t41 - t43; r[21] = -t50 + t48; - r[22] = v866 * (t55 - t58); + r[22] = v866 * (t55 - t58); r[23] = t63 - t61; - r[24] = 0.5000000000e0f * (t74 - t68 - t70 + t72); + r[24] = 0.5f *(t74 - t68 - t70 + t72); [unroll] for(uint i = 0; i < 5; ++i) { @@ -604,14 +604,14 @@ SH9Color RotateSH9(in SH9Color sh, in float3x3 rotation) { const float r00 = rotation._m00; const float r10 = rotation._m01; - const float r20 = -rotation._m02; + const float r20 = rotation._m02; const float r01 = rotation._m10; const float r11 = rotation._m11; - const float r21 = -rotation._m12; + const float r21 = rotation._m12; - const float r02 = -rotation._m20; - const float r12 = -rotation._m21; + const float r02 = rotation._m20; + const float r12 = rotation._m21; const float r22 = rotation._m22; SH9Color result; @@ -711,58 +711,58 @@ H4 ProjectOntoH4(in float3 dir, in float value) //------------------------------------------------------------------------------------------------- H4 ConvertToH4(in SH9 sh) { - const float rt2 = sqrt(2.0f); - const float rt32 = sqrt(3.0f / 2.0f); - const float rt52 = sqrt(5.0f / 2.0f); - const float rt152 = sqrt(15.0f / 2.0f); - const float convMatrix[4][9] = - { - { 1.0f / rt2, 0, 0.5f * rt32, 0, 0, 0, 0, 0, 0 }, - { 0, 1.0f / rt2, 0, 0, 0, (3.0f / 8.0f) * rt52, 0, 0, 0 }, - { 0, 0, 1.0f / (2.0f * rt2), 0, 0, 0, 0.25f * rt152, 0, 0 }, - { 0, 0, 0, 1.0f / rt2, 0, 0, 0, (3.0f / 8.0f) * rt52, 0 } - }; + const float rt2 = sqrt(2.0f); + const float rt32 = sqrt(3.0f / 2.0f); + const float rt52 = sqrt(5.0f / 2.0f); + const float rt152 = sqrt(15.0f / 2.0f); + const float convMatrix[4][9] = + { + { 1.0f / rt2, 0, 0.5f * rt32, 0, 0, 0, 0, 0, 0 }, + { 0, 1.0f / rt2, 0, 0, 0, (3.0f / 8.0f) * rt52, 0, 0, 0 }, + { 0, 0, 1.0f / (2.0f * rt2), 0, 0, 0, 0.25f * rt152, 0, 0 }, + { 0, 0, 0, 1.0f / rt2, 0, 0, 0, (3.0f / 8.0f) * rt52, 0 } + }; H4 hBasis; - [unroll] - for(uint row = 0; row < 4; ++row) - { - hBasis[row] = 0.0f; + [unroll] + for(uint row = 0; row < 4; ++row) + { + hBasis[row] = 0.0f; - [unroll] - for(uint col = 0; col < 9; ++col) - hBasis[row] += convMatrix[row][col] * sh.c[col]; - } + [unroll] + for(uint col = 0; col < 9; ++col) + hBasis[row] += convMatrix[row][col] * sh.c[col]; + } return hBasis; } H4Color ConvertToH4(in SH9Color sh) { - const float rt2 = sqrt(2.0f); - const float rt32 = sqrt(3.0f / 2.0f); - const float rt52 = sqrt(5.0f / 2.0f); - const float rt152 = sqrt(15.0f / 2.0f); - const float convMatrix[4][9] = - { - { 1.0f / rt2, 0, 0.5f * rt32, 0, 0, 0, 0, 0, 0 }, - { 0, 1.0f / rt2, 0, 0, 0, (3.0f / 8.0f) * rt52, 0, 0, 0 }, - { 0, 0, 1.0f / (2.0f * rt2), 0, 0, 0, 0.25f * rt152, 0, 0 }, - { 0, 0, 0, 1.0f / rt2, 0, 0, 0, (3.0f / 8.0f) * rt52, 0 } - }; + const float rt2 = sqrt(2.0f); + const float rt32 = sqrt(3.0f / 2.0f); + const float rt52 = sqrt(5.0f / 2.0f); + const float rt152 = sqrt(15.0f / 2.0f); + const float convMatrix[4][9] = + { + { 1.0f / rt2, 0, 0.5f * rt32, 0, 0, 0, 0, 0, 0 }, + { 0, 1.0f / rt2, 0, 0, 0, (3.0f / 8.0f) * rt52, 0, 0, 0 }, + { 0, 0, 1.0f / (2.0f * rt2), 0, 0, 0, 0.25f * rt152, 0, 0 }, + { 0, 0, 0, 1.0f / rt2, 0, 0, 0, (3.0f / 8.0f) * rt52, 0 } + }; H4Color hBasis; - [unroll] - for(uint row = 0; row < 4; ++row) - { - hBasis.c[row] = 0.0f; + [unroll] + for(uint row = 0; row < 4; ++row) + { + hBasis.c[row] = 0.0f; - [unroll] - for(uint col = 0; col < 9; ++col) - hBasis.c[row] += convMatrix[row][col] * sh.c[col]; - } + [unroll] + for(uint col = 0; col < 9; ++col) + hBasis.c[row] += convMatrix[row][col] * sh.c[col]; + } return hBasis; } @@ -772,17 +772,17 @@ H4Color ConvertToH4(in SH9Color sh) //------------------------------------------------------------------------------------------------- float EvalH4(in float3 n, in H4 hBasis) { - float result = 0.0f; + float result = 0.0f; // Band 0 result += hBasis.x * (1.0f / sqrt(2.0f * Pi)); // Band 1 - result += hBasis.y * sqrt(1.5f / Pi) * n.y; + result += hBasis.y * -sqrt(1.5f / Pi) * n.y; result += hBasis.z * sqrt(1.5f / Pi) * (2 * n.z - 1.0f); - result += hBasis.w * sqrt(1.5f / Pi) * n.x; + result += hBasis.w * -sqrt(1.5f / Pi) * n.x; - return result; + return result; } //------------------------------------------------------------------------------------------------- @@ -790,17 +790,17 @@ float EvalH4(in float3 n, in H4 hBasis) //------------------------------------------------------------------------------------------------- float3 EvalH4(in float3 n, in H4Color hBasis) { - float3 color = 0.0f; + float3 color = 0.0f; // Band 0 color += hBasis.c[0] * (1.0f / sqrt(2.0f * Pi)); // Band 1 - color += hBasis.c[1] * sqrt(1.5f / Pi) * n.y; + color += hBasis.c[1] * -sqrt(1.5f / Pi) * n.y; color += hBasis.c[2] * sqrt(1.5f / Pi) * (2 * n.z - 1.0f); - color += hBasis.c[3] * sqrt(1.5f / Pi) * n.x; + color += hBasis.c[3] * -sqrt(1.5f / Pi) * n.x; - return color; + return color; } //------------------------------------------------------------------------------------------------- @@ -818,46 +818,46 @@ float3 EvalH4(in float3 n, in float3 H0, in float3 H1, in float3 H2, in float3 H float HDotProduct(in H4 a, in H4 b) { - float result = 0.0f; + float result = 0.0f; - [unroll] - for(uint i = 0; i < 4; ++i) - result += a[i] * b[i]; + [unroll] + for(uint i = 0; i < 4; ++i) + result += a[i] * b[i]; - return result; + return result; } float3 HDotProduct(in H4Color a, in H4 b) { - float3 result = 0.0f; + float3 result = 0.0f; - [unroll] - for(uint i = 0; i < 4; ++i) - result += a.c[i] * b[i]; + [unroll] + for(uint i = 0; i < 4; ++i) + result += a.c[i] * b[i]; - return result; + return result; } float3 HDotProduct(in H4 a, in H4Color b) { - float3 result = 0.0f; + float3 result = 0.0f; - [unroll] - for(uint i = 0; i < 4; ++i) - result += a[i] * b.c[i]; + [unroll] + for(uint i = 0; i < 4; ++i) + result += a[i] * b.c[i]; - return result; + return result; } float3 HDotProduct(in H4Color a, in H4Color b) { - float3 result = 0.0f; + float3 result = 0.0f; - [unroll] - for(uint i = 0; i < 4; ++i) - result += a.c[i] * b.c[i]; + [unroll] + for(uint i = 0; i < 4; ++i) + result += a.c[i] * b.c[i]; - return result; + return result; } // == H6 ========================================================================================= @@ -868,128 +868,151 @@ float3 HDotProduct(in H4Color a, in H4Color b) //------------------------------------------------------------------------------------------------- H6 ConvertToH6(in SH9 sh) { - const float rt2 = sqrt(2.0f); - const float rt32 = sqrt(3.0f / 2.0f); - const float rt52 = sqrt(5.0f / 2.0f); - const float rt152 = sqrt(15.0f / 2.0f); - const float convMatrix[6][9] = - { - { 1.0f / rt2, 0, 0.5f * rt32, 0, 0, 0, 0, 0, 0 }, - { 0, 1.0f / rt2, 0, 0, 0, (3.0f / 8.0f) * rt52, 0, 0, 0 }, - { 0, 0, 1.0f / (2.0f * rt2), 0, 0, 0, 0.25f * rt152, 0, 0 }, - { 0, 0, 0, 1.0f / rt2, 0, 0, 0, (3.0f / 8.0f) * rt52, 0 }, + const float rt2 = sqrt(2.0f); + const float rt32 = sqrt(3.0f / 2.0f); + const float rt52 = sqrt(5.0f / 2.0f); + const float rt152 = sqrt(15.0f / 2.0f); + const float convMatrix[6][9] = + { + { 1.0f / rt2, 0, 0.5f * rt32, 0, 0, 0, 0, 0, 0 }, + { 0, 1.0f / rt2, 0, 0, 0, (3.0f / 8.0f) * rt52, 0, 0, 0 }, + { 0, 0, 1.0f / (2.0f * rt2), 0, 0, 0, 0.25f * rt152, 0, 0 }, + { 0, 0, 0, 1.0f / rt2, 0, 0, 0, (3.0f / 8.0f) * rt52, 0 }, { 0, 0, 0, 0, 1.0f / rt2, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1.0f / rt2 } - }; + }; H6 hBasis; - [unroll] - for(uint row = 0; row < 6; ++row) - { - hBasis.c[row] = 0.0f; + [unroll] + for(uint row = 0; row < 6; ++row) + { + hBasis.c[row] = 0.0f; - [unroll] - for(uint col = 0; col < 9; ++col) - hBasis.c[row] += convMatrix[row][col] * sh.c[col]; - } + [unroll] + for(uint col = 0; col < 9; ++col) + hBasis.c[row] += convMatrix[row][col] * sh.c[col]; + } return hBasis; } H6Color ConvertToH6(in SH9Color sh) { - const float rt2 = sqrt(2.0f); - const float rt32 = sqrt(3.0f / 2.0f); - const float rt52 = sqrt(5.0f / 2.0f); - const float rt152 = sqrt(15.0f / 2.0f); - const float convMatrix[6][9] = - { - { 1.0f / rt2, 0, 0.5f * rt32, 0, 0, 0, 0, 0, 0 }, - { 0, 1.0f / rt2, 0, 0, 0, (3.0f / 8.0f) * rt52, 0, 0, 0 }, - { 0, 0, 1.0f / (2.0f * rt2), 0, 0, 0, 0.25f * rt152, 0, 0 }, - { 0, 0, 0, 1.0f / rt2, 0, 0, 0, (3.0f / 8.0f) * rt52, 0 }, + const float rt2 = sqrt(2.0f); + const float rt32 = sqrt(3.0f / 2.0f); + const float rt52 = sqrt(5.0f / 2.0f); + const float rt152 = sqrt(15.0f / 2.0f); + const float convMatrix[6][9] = + { + { 1.0f / rt2, 0, 0.5f * rt32, 0, 0, 0, 0, 0, 0 }, + { 0, 1.0f / rt2, 0, 0, 0, (3.0f / 8.0f) * rt52, 0, 0, 0 }, + { 0, 0, 1.0f / (2.0f * rt2), 0, 0, 0, 0.25f * rt152, 0, 0 }, + { 0, 0, 0, 1.0f / rt2, 0, 0, 0, (3.0f / 8.0f) * rt52, 0 }, { 0, 0, 0, 0, 1.0f / rt2, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1.0f / rt2 } - }; + }; H6Color hBasis; - [unroll] - for(uint row = 0; row < 6; ++row) - { - hBasis.c[row] = 0.0f; + [unroll] + for(uint row = 0; row < 6; ++row) + { + hBasis.c[row] = 0.0f; - [unroll] - for(uint col = 0; col < 9; ++col) - hBasis.c[row] += convMatrix[row][col] * sh.c[col]; - } + [unroll] + for(uint col = 0; col < 9; ++col) + hBasis.c[row] += convMatrix[row][col] * sh.c[col]; + } return hBasis; } +//------------------------------------------------------------------------------------------------- +// Evalutes the 3-band H-Basis coefficients in the given direction +//------------------------------------------------------------------------------------------------- +float EvalH6(in float3 n, in H6 hBasis) +{ + float result = 0.0f; + + // Band 0 + result += hBasis.c[0] * (1.0f / sqrt(2.0f * Pi)); + + // Band 1 + result += hBasis.c[1] * -sqrt(1.5f / Pi) * n.y; + result += hBasis.c[2] * sqrt(1.5f / Pi) * (2 * n.z - 1.0f); + result += hBasis.c[3] * -sqrt(1.5f / Pi) * n.x; + + // Band 3 + result += hBasis.c[4] * 0.5f * sqrt(7.5f / Pi) * n.x * n.y; + result += hBasis.c[5] * 0.5f * sqrt(7.5f / Pi) * (n.x * n.x - n.y * n.y); + + return result; +} + + //------------------------------------------------------------------------------------------------- // Evalutes the 3-band H-Basis coefficients in the given direction //------------------------------------------------------------------------------------------------- float3 EvalH6(in float3 n, in H6Color hBasis) { - float3 color = 0.0f; + float3 color = 0.0f; // Band 0 color += hBasis.c[0] * (1.0f / sqrt(2.0f * Pi)); // Band 1 - color += hBasis.c[1] * sqrt(1.5f / Pi) * n.y; + color += hBasis.c[1] * -sqrt(1.5f / Pi) * n.y; color += hBasis.c[2] * sqrt(1.5f / Pi) * (2 * n.z - 1.0f); - color += hBasis.c[3] * sqrt(1.5f / Pi) * n.x; + color += hBasis.c[3] * -sqrt(1.5f / Pi) * n.x; // Band 3 color += hBasis.c[4] * 0.5f * sqrt(7.5f / Pi) * n.x * n.y; color += hBasis.c[5] * 0.5f * sqrt(7.5f / Pi) * (n.x * n.x - n.y * n.y); - return color; + return color; } float HDotProduct(in H6 a, in H6 b) { - float result = 0.0f; + float result = 0.0f; - [unroll] - for(uint i = 0; i < 6; ++i) - result += a.c[i] * b.c[i]; + [unroll] + for(uint i = 0; i < 6; ++i) + result += a.c[i] * b.c[i]; - return result; + return result; } float3 HDotProduct(in H6Color a, in H6 b) { - float3 result = 0.0f; + float3 result = 0.0f; - [unroll] - for(uint i = 0; i < 6; ++i) - result += a.c[i] * b.c[i]; + [unroll] + for(uint i = 0; i < 6; ++i) + result += a.c[i] * b.c[i]; - return result; + return result; } float3 HDotProduct(in H6 a, in H6Color b) { - float3 result = 0.0f; + float3 result = 0.0f; - [unroll] - for(uint i = 0; i < 6; ++i) - result += a.c[i] * b.c[i]; + [unroll] + for(uint i = 0; i < 6; ++i) + result += a.c[i] * b.c[i]; - return result; + return result; } float3 HDotProduct(in H6Color a, in H6Color b) { - float3 result = 0.0f; + float3 result = 0.0f; - [unroll] - for(uint i = 0; i < 6; ++i) - result += a.c[i] * b.c[i]; + [unroll] + for(uint i = 0; i < 6; ++i) + result += a.c[i] * b.c[i]; - return result; + return result; } \ No newline at end of file diff --git a/SampleFramework11/v1.02/Shaders/Sampling.hlsl b/SampleFramework11/v1.02/Shaders/Sampling.hlsl new file mode 100644 index 0000000..c97e1bb --- /dev/null +++ b/SampleFramework11/v1.02/Shaders/Sampling.hlsl @@ -0,0 +1,337 @@ +//================================================================================================= +// +// MJP's DX12 Sample Framework +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +#ifndef SAMPLING_HLSL_ +#define SAMPLING_HLSL_ + +#include + +// Maps a value inside the square [0,1]x[0,1] to a value in a disk of radius 1 using concentric squares. +// This mapping preserves area, bi continuity, and minimizes deformation. +// Based off the algorithm "A Low Distortion Map Between Disk and Square" by Peter Shirley and +// Kenneth Chiu. Also includes polygon morphing modification from "CryEngine3 Graphics Gems" +// by Tiago Sousa +float2 SquareToConcentricDiskMapping(float x, float y, float numSides, float polygonAmount) +{ + float phi, r; + + // -- (a,b) is now on [-1,1]ˆ2 + float a = 2.0f * x - 1.0f; + float b = 2.0f * y - 1.0f; + + if(a > -b) // region 1 or 2 + { + if(a > b) // region 1, also |a| > |b| + { + r = a; + phi = (Pi / 4.0f) * (b / a); + } + else // region 2, also |b| > |a| + { + r = b; + phi = (Pi / 4.0f) * (2.0f - (a / b)); + } + } + else // region 3 or 4 + { + if(a < b) // region 3, also |a| >= |b|, a != 0 + { + r = -a; + phi = (Pi / 4.0f) * (4.0f + (b / a)); + } + else // region 4, |b| >= |a|, but a==0 and b==0 could occur. + { + r = -b; + if(b != 0) + phi = (Pi / 4.0f) * (6.0f - (a / b)); + else + phi = 0; + } + } + + const float N = numSides; + float polyModifier = cos(Pi / N) / cos(phi - (Pi2 / N) * floor((N * phi + Pi) / Pi2)); + r *= lerp(1.0f, polyModifier, polygonAmount); + + float2 result; + result.x = r * cos(phi); + result.y = r * sin(phi); + + return result; +} + +// Maps a value inside the square [0,1]x[0,1] to a value in a disk of radius 1 using concentric squares. +// This mapping preserves area, bi continuity, and minimizes deformation. +// Based off the algorithm "A Low Distortion Map Between Disk and Square" by Peter Shirley and +// Kenneth Chiu. +float2 SquareToConcentricDiskMapping(float x, float y) +{ + float phi = 0.0f; + float r = 0.0f; + + // -- (a,b) is now on [-1,1]ˆ2 + float a = 2.0f * x - 1.0f; + float b = 2.0f * y - 1.0f; + + if(a > -b) // region 1 or 2 + { + if(a > b) // region 1, also |a| > |b| + { + r = a; + phi = (Pi / 4.0f) * (b / a); + } + else // region 2, also |b| > |a| + { + r = b; + phi = (Pi / 4.0f) * (2.0f - (a / b)); + } + } + else // region 3 or 4 + { + if(a < b) // region 3, also |a| >= |b|, a != 0 + { + r = -a; + phi = (Pi / 4.0f) * (4.0f + (b / a)); + } + else // region 4, |b| >= |a|, but a==0 and b==0 could occur. + { + r = -b; + if(b != 0) + phi = (Pi / 4.0f) * (6.0f - (a / b)); + else + phi = 0; + } + } + + float2 result; + result.x = r * cos(phi); + result.y = r * sin(phi); + return result; +} + +// Returns a random direction for sampling a GGX distribution (in tangent space) +float3 SampleDirectionGGX(float3 v, float3 n, float roughness, float u1, float u2) +{ + float theta = atan2(roughness * sqrt(u1), sqrt(1 - u1)); + float phi = 2 * Pi * u2; + + float3 h; + h.x = sin(theta) * cos(phi); + h.y = sin(theta) * sin(phi); + h.z = cos(theta); + + float hDotV = abs(dot(h, v)); + float3 sampleDir = 2.0f * hDotV * h - v; + return normalize(sampleDir); +} + +float3 SampleGGXVisibleNormal(float3 wo, float ax, float ay, float u1, float u2) +{ + // Stretch the view vector so we are sampling as though + // roughness==1 + float3 v = normalize(float3(wo.x * ax, wo.y * ay, wo.z)); + + // Build an orthonormal basis with v, t1, and t2 + float3 t1 = (v.z < 0.999f) ? normalize(cross(v, float3(0, 0, 1))) : float3(1, 0, 0); + float3 t2 = cross(t1, v); + + // Choose a point on a disk with each half of the disk weighted + // proportionally to its projection onto direction v + float a = 1.0f / (1.0f + v.z); + float r = sqrt(u1); + float phi = (u2 < a) ? (u2 / a) * Pi : Pi + (u2 - a) / (1.0f - a) * Pi; + float p1 = r * cos(phi); + float p2 = r * sin(phi) * ((u2 < a) ? 1.0f : v.z); + + // Calculate the normal in this stretched tangent space + float3 n = p1 * t1 + p2 * t2 + sqrt(max(0.0f, 1.0f - p1 * p1 - p2 * p2)) * v; + + // Unstretch and normalize the normal + return normalize(float3(ax * n.x, ay * n.y, max(0.0f, n.z))); +} + +// Returns a random direction on the unit sphere +float3 SampleDirectionSphere(float u1, float u2) +{ + float z = u1 * 2.0f - 1.0f; + float r = sqrt(max(0.0f, 1.0f - z * z)); + float phi = 2 * Pi * u2; + float x = r * cos(phi); + float y = r * sin(phi); + + return float3(x, y, z); +} + +// Returns a random direction on the hemisphere around z = 1 +float3 SampleDirectionHemisphere(float u1, float u2) +{ + float z = u1; + float r = sqrt(max(0.0f, 1.0f - z * z)); + float phi = 2 * Pi * u2; + float x = r * cos(phi); + float y = r * sin(phi); + + return float3(x, y, z); +} + +// Returns a random cosine-weighted direction on the hemisphere around z = 1 +float3 SampleDirectionCosineHemisphere(float u1, float u2) +{ + float2 uv = SquareToConcentricDiskMapping(u1, u2); + float u = uv.x; + float v = uv.y; + + // Project samples on the disk to the hemisphere to get a + // cosine weighted distribution + float3 dir; + float r = u * u + v * v; + dir.x = u; + dir.y = v; + dir.z = sqrt(max(0.0f, 1.0f - r)); + + return dir; +} + +// Returns a random direction from within a cone with angle == theta +float3 SampleDirectionCone(float u1, float u2, float cosThetaMax) +{ + float cosTheta = (1.0f - u1) + u1 * cosThetaMax; + float sinTheta = sqrt(1.0f - cosTheta * cosTheta); + float phi = u2 * 2.0f * Pi; + return float3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta); +} + +// Returns a direction that samples a rectangular area light +float3 SampleDirectionRectangularLight(float u1, float u2, float3 sourcePos, float2 lightSize, float3 lightPos, + Quaternion lightOrientation, float distanceToLight) +{ + float x = u1 - 0.5f; + float y = u2 - 0.5f; + + float3x3 lightBasis = QuatTo3x3(lightOrientation); + float3 lightBasisX = lightBasis._11_12_13; + float3 lightBasisY = lightBasis._21_22_23; + float3 lightBasisZ = lightBasis._31_32_33; + + // Pick random sample point + float3 samplePos = lightPos + + lightBasisX * x * lightSize.x + + lightBasisY * y * lightSize.y; + + float3 sampleDir = samplePos - sourcePos; + distanceToLight = length(sampleDir); + if(distanceToLight > 0.0f) + sampleDir /= distanceToLight; + + return sampleDir; +} + +// Returns the PDF for a particular GGX sample +float SampleDirectionGGX_PDF(float3 n, float3 h, float3 v, float roughness) +{ + float nDotH = saturate(dot(n, h)); + float hDotV = saturate(dot(h, v)); + float m2 = roughness * roughness; + float x = nDotH * nDotH * (m2 - 1) + 1; + float d = m2 / (Pi * x * x); + float pM = d * nDotH; + return pM / (4 * hDotV); +} + +// Returns the (constant) PDF of sampling uniform directions on the unit sphere +float SampleDirectionSphere_PDF() +{ + return 1.0f / (Pi * 4.0f); +} + +// Returns the (constant) PDF of sampling uniform directions on a unit hemisphere +float SampleDirectionHemisphere_PDF() +{ + return 1.0f / (Pi * 2.0f); +} + +// Returns the PDF of of a single sample on a cosine-weighted hemisphere +float SampleDirectionCosineHemisphere_PDF(float cosTheta) +{ + return cosTheta / Pi; +} + +// Returns the PDF of of a single sample on a cosine-weighted hemisphere +float SampleDirectionCosineHemisphere_PDF(float3 normal, float3 sampleDir) +{ + return saturate(dot(normal, sampleDir)) / Pi; +} + +// Returns the PDF of of a single uniform sample within a cone +float SampleDirectionCone_PDF(float cosThetaMax) +{ + return 1.0f / (2.0f * Pi * (1.0f - cosThetaMax)); +} + +// Returns the PDF of of a single sample on a rectangular area light +float SampleDirectionRectangularLight_PDF(float2 lightSize, float3 sampleDir, Quaternion lightOrientation, float distanceToLight) +{ + float3 lightBasisZ = QuatRotate(float3(0.0f, 0.0f, -1.0f), lightOrientation); + float areaNDotL = saturate(dot(sampleDir, lightBasisZ)); + return (distanceToLight * distanceToLight) / (areaNDotL * lightSize.x * lightSize.y); +} + +uint CMJPermute(uint i, uint l, uint p) +{ + uint w = l - 1; + w |= w >> 1; + w |= w >> 2; + w |= w >> 4; + w |= w >> 8; + w |= w >> 16; + do + { + i ^= p; i *= 0xe170893d; + i ^= p >> 16; + i ^= (i & w) >> 4; + i ^= p >> 8; i *= 0x0929eb3f; + i ^= p >> 23; + i ^= (i & w) >> 1; i *= 1 | p >> 27; + i *= 0x6935fa69; + i ^= (i & w) >> 11; i *= 0x74dcb303; + i ^= (i & w) >> 2; i *= 0x9e501cc3; + i ^= (i & w) >> 2; i *= 0xc860a3df; + i &= w; + i ^= i >> 5; + } + while (i >= l); + return (i + p) % l; +} + +float CMJRandFloat(uint i, uint p) +{ + i ^= p; + i ^= i >> 17; + i ^= i >> 10; i *= 0xb36534e5; + i ^= i >> 12; + i ^= i >> 21; i *= 0x93fc4795; + i ^= 0xdf6e307f; + i ^= i >> 17; i *= 1 | p >> 18; + return i * (1.0f / 4294967808.0f); +} + + // Returns a 2D sample from a particular pattern using correlated multi-jittered sampling [Kensler 2013] +float2 SampleCMJ2D(uint sampleIdx, uint numSamplesX, uint numSamplesY, uint pattern) +{ + uint N = numSamplesX * numSamplesY; + sampleIdx = CMJPermute(sampleIdx, N, pattern * 0x51633e2d); + uint sx = CMJPermute(sampleIdx % numSamplesX, numSamplesX, pattern * 0x68bc21eb); + uint sy = CMJPermute(sampleIdx / numSamplesX, numSamplesY, pattern * 0x02e5be93); + float jx = CMJRandFloat(sampleIdx, pattern * 0x967a889b); + float jy = CMJRandFloat(sampleIdx, pattern * 0x368cc8b7); + return float2((sx + (sy + jx) / numSamplesY) / numSamplesX, (sampleIdx + jy) / N); +} + + +#endif // SAMPLING_HLSL_ \ No newline at end of file diff --git a/SampleFramework11/v1.02/Utility.h b/SampleFramework11/v1.02/Utility.h index 42c0731..92071ef 100644 --- a/SampleFramework11/v1.02/Utility.h +++ b/SampleFramework11/v1.02/Utility.h @@ -1,198 +1,212 @@ -//================================================================================================= -// -// MJP's DX11 Sample Framework -// http://mynameismjp.wordpress.com/ -// -// All code licensed under the MIT license -// -//================================================================================================= - -#pragma once - -#include "PCH.h" - -#include "Exceptions.h" -#include "InterfacePointers.h" -#include "SF11_Math.h" -#include "Assert.h" - -namespace SampleFramework11 -{ - -// Returns a size suitable for creating a constant buffer, by rounding up -// to the next multiple of 16 -inline UINT CBSize(UINT size) -{ - return ((size + 15) / 16) * 16; -} - -// Converts an ANSI string to a std::wstring -inline std::wstring AnsiToWString(const char* ansiString) -{ - wchar buffer[512]; - Win32Call(MultiByteToWideChar(CP_ACP, 0, ansiString, -1, buffer, 512)); - return std::wstring(buffer); -} - -inline std::string WStringToAnsi(const wchar* wideString) -{ - char buffer[512]; - Win32Call(WideCharToMultiByte(CP_ACP, 0, wideString, -1, buffer, 612, NULL, NULL)); - return std::string(buffer); -} - -// Splits up a string using a delimiter -inline void Split(const std::wstring& str, std::vector& parts, const std::wstring& delimiters = L" ") -{ - // Skip delimiters at beginning - std::wstring::size_type lastPos = str.find_first_not_of(delimiters, 0); - - // Find first "non-delimiter" - std::wstring::size_type pos = str.find_first_of(delimiters, lastPos); - - while (std::wstring::npos != pos || std::wstring::npos != lastPos) - { - // Found a token, add it to the vector - parts.push_back(str.substr(lastPos, pos - lastPos)); - - // Skip delimiters. Note the "not_of" - lastPos = str.find_first_not_of(delimiters, pos); - - // Find next "non-delimiter" - pos = str.find_first_of(delimiters, lastPos); - } -} - -// Splits up a string using a delimiter -inline std::vector Split(const std::wstring& str, const std::wstring& delimiters = L" ") -{ - std::vector parts; - Split(str, parts, delimiters); - return parts; -} - -// Parses a string into a number -template inline T Parse(const std::wstring& str) -{ - std::wistringstream stream(str); - wchar_t c; - T x; - if(!(str >> x) || stream.get(c)) - throw Exception(L"Can't parse string \"" + str + L"\""); - return x; -} - -// Converts a number to a string -template inline std::wstring ToString(const T& val) -{ - std::wostringstream stream; - if(!(stream << val)) - throw Exception(L"Error converting value to string"); - return stream.str(); -} - -// Converts a number to an ansi string -template inline std::string ToAnsiString(const T& val) -{ - std::ostringstream stream; - if(!(stream << val)) - throw Exception(L"Error converting value to string"); - return stream.str(); -} - -void PrintStringW(const wchar* format, ...); -void PrintString(const char* format, ...); - -std::wstring MakeString(const wchar* format, ...); -std::string MakeAnsiString(const char* format, ...); - -std::wstring SampleFrameworkDir(); - -// Outputs a string to the debugger output and stdout -inline void DebugPrint(const std::wstring& str) -{ - std::wstring output = str + L"\n"; - OutputDebugStringW(output.c_str()); - std::printf("%ls", output.c_str()); -} - -// Returns the number of mip levels given a texture size -inline UINT NumMipLevels(UINT width, UINT height) -{ - UINT numMips = 0; - UINT size = std::max(width, height); - while (1U << numMips <= size) - ++numMips; - - if (1U << numMips < size) - ++numMips; - - return numMips; -} - -// Gets an index from an index buffer -inline uint32 GetIndex(const void* indices, uint32 idx, uint32 indexSize) -{ - if(indexSize == 2) - return reinterpret_cast(indices)[idx]; - else - return reinterpret_cast(indices)[idx]; -} - -// Sets the viewport for a given render target size -inline void SetViewport(ID3D11DeviceContext* context, uint32 rtWidth, uint32 rtHeight) -{ - D3D11_VIEWPORT viewport; - viewport.Width = static_cast(rtWidth); - viewport.Height = static_cast(rtHeight); - viewport.MinDepth = 0.0f; - viewport.MaxDepth = 1.0f; - viewport.TopLeftX = 0.0f; - viewport.TopLeftY = 0.0f; - - context->RSSetViewports(1, &viewport); -} - -// Copies a portion of a buffer to another buffer -inline void CopyBufferRegion(ID3D11DeviceContext* context, ID3D11Buffer* dstBuffer, ID3D11Buffer* srcBuffer, - uint32 dstOffset, uint32 srcOffset, uint32 srcSize) -{ - D3D11_BOX srcBox; - srcBox.left = srcOffset; - srcBox.right = srcOffset + srcSize; - srcBox.top = 0; - srcBox.bottom = 1; - srcBox.front = 0; - srcBox.back = 1; - context->CopySubresourceRegion(dstBuffer, 0, dstOffset, 0, 0, srcBuffer, 0, &srcBox); -} - -template -uint64 ArraySize(T(&)[N]) -{ - return N; -} - -#define ArraySize_(x) ((sizeof(x) / sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) - -// Barycentric coordinate functions -XMFLOAT3 CartesianToBarycentric(float x, float y, const XMFLOAT2& pos1, const XMFLOAT2& pos2, const XMFLOAT2& pos3); -XMFLOAT2 BarycentricToCartesian(const XMFLOAT3& r, const XMFLOAT2& pos1, const XMFLOAT2& pos2, const XMFLOAT2& pos3); -XMVECTOR BarycentricToCartesian(const XMFLOAT3& r, FXMVECTOR pos1, FXMVECTOR pos2, FXMVECTOR pos3); -BOOL PointIsInTriangle(const XMFLOAT3& r, float epsilon = 0.0f); - -// Compute shader helpers -uint32 DispatchSize(uint32 tgSize, uint32 numElements); -void SetCSInputs(ID3D11DeviceContext* context, ID3D11ShaderResourceView* srv0, ID3D11ShaderResourceView* srv1 = NULL, - ID3D11ShaderResourceView* srv2 = NULL, ID3D11ShaderResourceView* srv3 = NULL); -void ClearCSInputs(ID3D11DeviceContext* context); -void SetCSOutputs(ID3D11DeviceContext* context, ID3D11UnorderedAccessView* uav0, ID3D11UnorderedAccessView* uav1 = NULL, - ID3D11UnorderedAccessView* uav2 = NULL, ID3D11UnorderedAccessView* uav3 = NULL, - ID3D11UnorderedAccessView* uav4 = NULL, ID3D11UnorderedAccessView* uav5 = NULL); -void ClearCSOutputs(ID3D11DeviceContext* context); -void SetCSSamplers(ID3D11DeviceContext* context, ID3D11SamplerState* sampler0, ID3D11SamplerState* sampler1 = NULL, - ID3D11SamplerState* sampler2 = NULL, ID3D11SamplerState* sampler3 = NULL); -void SetCSShader(ID3D11DeviceContext* context, ID3D11ComputeShader* shader); -void SetCSConstants(ID3D11DeviceContext* context, ID3D11Buffer* constantBuffer, uint32 slot); - +//================================================================================================= +// +// MJP's DX11 Sample Framework +// http://mynameismjp.wordpress.com/ +// +// All code licensed under the MIT license +// +//================================================================================================= + +#pragma once + +#include "PCH.h" + +#include "Exceptions.h" +#include "InterfacePointers.h" +#include "SF11_Math.h" +#include "Assert.h" + +namespace SampleFramework11 +{ + +// Returns a size suitable for creating a constant buffer, by rounding up +// to the next multiple of 16 +inline UINT CBSize(UINT size) +{ + return ((size + 15) / 16) * 16; +} + +// Converts an ANSI string to a std::wstring +inline std::wstring AnsiToWString(const char* ansiString) +{ + wchar buffer[512]; + Win32Call(MultiByteToWideChar(CP_ACP, 0, ansiString, -1, buffer, 512)); + return std::wstring(buffer); +} + +inline std::string WStringToAnsi(const wchar* wideString) +{ + char buffer[512]; + Win32Call(WideCharToMultiByte(CP_ACP, 0, wideString, -1, buffer, 612, NULL, NULL)); + return std::string(buffer); +} + +// Splits up a string using a delimiter +inline void Split(const std::wstring& str, std::vector& parts, const std::wstring& delimiters = L" ") +{ + // Skip delimiters at beginning + std::wstring::size_type lastPos = str.find_first_not_of(delimiters, 0); + + // Find first "non-delimiter" + std::wstring::size_type pos = str.find_first_of(delimiters, lastPos); + + while (std::wstring::npos != pos || std::wstring::npos != lastPos) + { + // Found a token, add it to the vector + parts.push_back(str.substr(lastPos, pos - lastPos)); + + // Skip delimiters. Note the "not_of" + lastPos = str.find_first_not_of(delimiters, pos); + + // Find next "non-delimiter" + pos = str.find_first_of(delimiters, lastPos); + } +} + +// Splits up a string using a delimiter +inline std::vector Split(const std::wstring& str, const std::wstring& delimiters = L" ") +{ + std::vector parts; + Split(str, parts, delimiters); + return parts; +} + +// Parses a string into a number +template inline T Parse(const std::wstring& str) +{ + std::wistringstream stream(str); + wchar_t c; + T x; + if(!(str >> x) || stream.get(c)) + throw Exception(L"Can't parse string \"" + str + L"\""); + return x; +} + +// Converts a number to a string +template inline std::wstring ToString(const T& val) +{ + std::wostringstream stream; + if(!(stream << val)) + throw Exception(L"Error converting value to string"); + return stream.str(); +} + +// Converts a number to an ansi string +template inline std::string ToAnsiString(const T& val) +{ + std::ostringstream stream; + if(!(stream << val)) + throw Exception(L"Error converting value to string"); + return stream.str(); +} + +void PrintStringW(const wchar* format, ...); +void PrintString(const char* format, ...); + +std::wstring MakeString(const wchar* format, ...); +std::string MakeAnsiString(const char* format, ...); + +std::wstring SampleFrameworkDir(); + +// Outputs a string to the debugger output and stdout +inline void DebugPrint(const std::wstring& str) +{ + std::wstring output = str + L"\n"; + OutputDebugStringW(output.c_str()); + std::printf("%ls", output.c_str()); +} + +// Returns the number of mip levels given a texture size +inline uint32 NumMipLevels(uint32 width, uint32 height) +{ + uint32 numMips = 0; + uint32 size = std::max(width, height); + while (1U << numMips <= size) + ++numMips; + + if (1U << numMips < size) + ++numMips; + + return numMips; +} + +inline uint32 NumMipLevels(uint32 width, uint32 height, uint32 depth) +{ + uint32 numMips = 0; + uint32 size = std::max(width, height); + size = std::max(size, depth); + while (1U << numMips <= size) + ++numMips; + + if (1U << numMips < size) + ++numMips; + + return numMips; +} + +// Gets an index from an index buffer +inline uint32 GetIndex(const void* indices, uint32 idx, uint32 indexSize) +{ + if(indexSize == 2) + return reinterpret_cast(indices)[idx]; + else + return reinterpret_cast(indices)[idx]; +} + +// Sets the viewport for a given render target size +inline void SetViewport(ID3D11DeviceContext* context, uint32 rtWidth, uint32 rtHeight) +{ + D3D11_VIEWPORT viewport; + viewport.Width = static_cast(rtWidth); + viewport.Height = static_cast(rtHeight); + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; + viewport.TopLeftX = 0.0f; + viewport.TopLeftY = 0.0f; + + context->RSSetViewports(1, &viewport); +} + +// Copies a portion of a buffer to another buffer +inline void CopyBufferRegion(ID3D11DeviceContext* context, ID3D11Buffer* dstBuffer, ID3D11Buffer* srcBuffer, + uint32 dstOffset, uint32 srcOffset, uint32 srcSize) +{ + D3D11_BOX srcBox; + srcBox.left = srcOffset; + srcBox.right = srcOffset + srcSize; + srcBox.top = 0; + srcBox.bottom = 1; + srcBox.front = 0; + srcBox.back = 1; + context->CopySubresourceRegion(dstBuffer, 0, dstOffset, 0, 0, srcBuffer, 0, &srcBox); +} + +template +uint64 ArraySize(T(&)[N]) +{ + return N; +} + +#define ArraySize_(x) ((sizeof(x) / sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) + +// Barycentric coordinate functions +XMFLOAT3 CartesianToBarycentric(float x, float y, const XMFLOAT2& pos1, const XMFLOAT2& pos2, const XMFLOAT2& pos3); +XMFLOAT2 BarycentricToCartesian(const XMFLOAT3& r, const XMFLOAT2& pos1, const XMFLOAT2& pos2, const XMFLOAT2& pos3); +XMVECTOR BarycentricToCartesian(const XMFLOAT3& r, FXMVECTOR pos1, FXMVECTOR pos2, FXMVECTOR pos3); +BOOL PointIsInTriangle(const XMFLOAT3& r, float epsilon = 0.0f); + +// Compute shader helpers +uint32 DispatchSize(uint32 tgSize, uint32 numElements); +void SetCSInputs(ID3D11DeviceContext* context, ID3D11ShaderResourceView* srv0, ID3D11ShaderResourceView* srv1 = NULL, + ID3D11ShaderResourceView* srv2 = NULL, ID3D11ShaderResourceView* srv3 = NULL); +void ClearCSInputs(ID3D11DeviceContext* context); +void SetCSOutputs(ID3D11DeviceContext* context, ID3D11UnorderedAccessView* uav0, ID3D11UnorderedAccessView* uav1 = NULL, + ID3D11UnorderedAccessView* uav2 = NULL, ID3D11UnorderedAccessView* uav3 = NULL, + ID3D11UnorderedAccessView* uav4 = NULL, ID3D11UnorderedAccessView* uav5 = NULL); +void ClearCSOutputs(ID3D11DeviceContext* context); +void SetCSSamplers(ID3D11DeviceContext* context, ID3D11SamplerState* sampler0, ID3D11SamplerState* sampler1 = NULL, + ID3D11SamplerState* sampler2 = NULL, ID3D11SamplerState* sampler3 = NULL); +void SetCSShader(ID3D11DeviceContext* context, ID3D11ComputeShader* shader); +void SetCSConstants(ID3D11DeviceContext* context, ID3D11Buffer* constantBuffer, uint32 slot); + } \ No newline at end of file