aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorMarco Foco <[email protected]>2016-03-07 15:47:07 +0100
committerMarco Foco <[email protected]>2016-03-08 16:04:19 +0100
commitcd6e0492903f8a9eb5efa14263d7d9ab092517de (patch)
tree05c010b75bf777335565819dcceb140886c5a7e9 /include
downloadfaceworks-cd6e0492903f8a9eb5efa14263d7d9ab092517de.tar.xz
faceworks-cd6e0492903f8a9eb5efa14263d7d9ab092517de.zip
FaceWorks 1.0
Diffstat (limited to 'include')
-rw-r--r--include/GFSDK_FaceWorks.h499
-rw-r--r--include/GFSDK_FaceWorks.hlsli572
2 files changed, 1071 insertions, 0 deletions
diff --git a/include/GFSDK_FaceWorks.h b/include/GFSDK_FaceWorks.h
new file mode 100644
index 0000000..c2af9a9
--- /dev/null
+++ b/include/GFSDK_FaceWorks.h
@@ -0,0 +1,499 @@
+//----------------------------------------------------------------------------------
+// File: FaceWorks/include/GFSDK_FaceWorks.h
+// SDK Version: v1.0
+// Site: http://developer.nvidia.com/
+//
+// Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// * Neither the name of NVIDIA CORPORATION nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//----------------------------------------------------------------------------------
+
+/// \file GFSDK_FaceWorks.h
+/// NVIDIA FaceWorks
+/// ----------------
+/// v1.00
+///
+/// FaceWorks is a middleware library for high-quality skin rendering, inspired by the
+/// techniques used in NVIDIA's "Digital Ira" demo.
+/// (http://www.nvidia.com/coolstuff/demos#!/lifelike-human-face-rendering)
+///
+/// Digital Ira is a tech demo, created by NVIDIA in collaboration with Dr. Paul Debevec's team at USC,
+/// in which a high-resolution head scan and performance capture are rendered as realistically as
+/// possible in real-time, using every rendering technique the demo team could think of. FaceWorks, in
+/// contrast, aims to be a reusable, production-ready library, with the goal of enabling game developers
+/// to match the rendering quality of Digital Ira.
+///
+/// FaceWorks currently provides two main features:
+///
+/// * A high-quality, efficient subsurface scattering solution, which supports both direct and ambient
+/// light.
+/// * An implementation of deep scattering (translucency) for direct light, based on estimating
+/// thickness from a shadow map.
+///
+/// Currently, Direct3D 11 is the only API supported by FaceWorks.
+///
+/// For detailed documentation please see doc/html/ in the archive.
+/// A sample application can be found in the samples/ subdirectory.
+
+
+#ifndef GFSDK_FACEWORKS_H
+#define GFSDK_FACEWORKS_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#pragma pack(push, 8) // Make sure we have consistent structure packings
+
+// =================================================================================
+// Preliminaries
+// =================================================================================
+
+#ifndef __GFSDK_COMMON_AUTOCONFIG
+# define __GFSDK_COMMON_AUTOCONFIG
+# ifdef __GNUC__
+# define __GFSDK_CC_GNU__ 1
+# define __GFSDK_CC_MSVC__ 0
+# else
+# define __GFSDK_CC_GNU__ 0
+# define __GFSDK_CC_MSVC__ 1
+# endif
+#endif
+
+#ifndef __GFSDK_COMMON_TYPES
+# define __GFSDK_COMMON_TYPES
+
+ typedef unsigned char gfsdk_U8;
+ typedef unsigned short gfsdk_U16;
+ typedef signed int gfsdk_S32;
+ typedef signed long long gfsdk_S64;
+ typedef unsigned int gfsdk_U32;
+ typedef unsigned long long gfsdk_U64;
+ typedef float gfsdk_F32;
+
+ typedef struct {
+ gfsdk_F32 x;
+ gfsdk_F32 y;
+ } gfsdk_float2;
+
+ typedef struct {
+ gfsdk_F32 x;
+ gfsdk_F32 y;
+ gfsdk_F32 z;
+ } gfsdk_float3;
+
+ typedef struct {
+ gfsdk_F32 x;
+ gfsdk_F32 y;
+ gfsdk_F32 z;
+ gfsdk_F32 w;
+ } gfsdk_float4;
+
+ // implicit row major
+ typedef struct {
+ gfsdk_F32 _11, _12, _13, _14;
+ gfsdk_F32 _21, _22, _23, _24;
+ gfsdk_F32 _31, _32, _33, _34;
+ gfsdk_F32 _41, _42, _43, _44;
+ } gfsdk_float4x4;
+
+ typedef bool gfsdk_bool;
+ typedef char gfsdk_char;
+ typedef const gfsdk_char* gfsdk_cstr;
+ typedef double gfsdk_F64;
+
+#endif // __GFSDK_COMMON_TYPES
+
+#ifndef __GFSDK_COMMON_MACROS
+# define __GFSDK_COMMON_MACROS
+// GNU
+# if __GFSDK_CC_GNU__
+# define __GFSDK_ALIGN__(bytes) __attribute__((aligned (bytes)))
+# define __GFSDK_EXPECT__(exp,tf) __builtin_expect(exp, tf)
+# define __GFSDK_INLINE__ __attribute__((always_inline))
+# define __GFSDK_NOLINE__ __attribute__((noinline))
+# define __GFSDK_RESTRICT__ __restrict
+# define __GFSDK_CDECL__
+# define __GFSDK_IMPORT__
+# define __GFSDK_EXPORT__
+# define __GFSDK_STDCALL__
+# endif
+
+// MSVC
+# if __GFSDK_CC_MSVC__
+# define __GFSDK_ALIGN__(bytes) __declspec(align(bytes))
+# define __GFSDK_EXPECT__(exp, tf) (exp)
+# define __GFSDK_INLINE__ __forceinline
+# define __GFSDK_NOINLINE__
+# define __GFSDK_RESTRICT__ __restrict
+# define __GFSDK_CDECL__ __cdecl
+# define __GFSDK_IMPORT__ __declspec(dllimport)
+# define __GFSDK_EXPORT__ __declspec(dllexport)
+# define __GFSDK_STDCALL__ __stdcall
+# endif
+#endif // __GFSDK_COMMON_MACROS
+
+// Custom heap allocator
+#ifndef __GFSDK_COMMON_CUSTOMHEAP
+# define __GFSDK_COMMON_CUSTOMHEAP
+
+ typedef struct {
+ void* (*new_)(size_t);
+ void (*delete_)(void*);
+ } gfsdk_new_delete_t;
+
+#endif // __GFSDK_COMMON_CUSTOMHEAP
+
+#define GFSDK_FACEWORKS_CALLCONV __GFSDK_CDECL__
+#if defined(GFSDK_FACEWORKS_EXPORTS)
+# define GFSDK_FACEWORKS_API extern "C" __GFSDK_EXPORT__
+#else
+# define GFSDK_FACEWORKS_API extern "C" __GFSDK_IMPORT__
+#endif
+
+
+
+// =================================================================================
+// Versioning
+// =================================================================================
+
+/// Header version number - used to check that the header matches the DLL.
+#define GFSDK_FaceWorks_HeaderVersion 100
+
+/// Retrieves the version number of the .dll actually being used
+/// \return the binary version as an integer (version is multiplied by 100)
+GFSDK_FACEWORKS_API int GFSDK_FACEWORKS_CALLCONV GFSDK_FaceWorks_GetBinaryVersion();
+
+/// Retrive baked-in build info string (branch, date/time, versions, etc.)
+///
+/// \return a null-terminated char string containing the build information
+GFSDK_FACEWORKS_API const char * GFSDK_FACEWORKS_CALLCONV GFSDK_FaceWorks_GetBuildInfo();
+
+
+
+// =================================================================================
+// Error handling
+// =================================================================================
+
+/// Error codes for return values.
+typedef enum
+{
+ GFSDK_FaceWorks_OK, ///< Everything ok
+ GFSDK_FaceWorks_InvalidArgument, ///< A required argument is NULL, or not in the valid range
+ GFSDK_FaceWorks_OutOfMemory, ///< Couldn't allocate memory
+ GFSDK_FaceWorks_VersionMismatch, ///< Header version doesn't match DLL version
+} GFSDK_FaceWorks_Result;
+
+/// \brief Error blob, for returning verbose error messages.
+/// \details Functions that take/return an error blob will allocate storage for the error message if
+/// necessary, using the custom allocator if present, and fill in m_msg.
+typedef struct
+{
+ gfsdk_new_delete_t m_allocator; ///< [in] Custom allocator (fill with nullptr if not used)
+ char * m_msg; ///< [out] Null-terminated error message
+} GFSDK_FaceWorks_ErrorBlob;
+
+/// Free the storage for the message in an error blob
+///
+/// \param pBlob the error blob object
+GFSDK_FACEWORKS_API void GFSDK_FACEWORKS_CALLCONV GFSDK_FaceWorks_FreeErrorBlob(GFSDK_FaceWorks_ErrorBlob * pBlob);
+
+
+
+// =================================================================================
+// Initialization
+// =================================================================================
+
+/// Internal initialization function. Should not be called directly.
+GFSDK_FACEWORKS_API GFSDK_FaceWorks_Result GFSDK_FACEWORKS_CALLCONV GFSDK_FaceWorks_Init_Internal(int headerVersion);
+
+/// Initialize FaceWorks, and checks that the header version matches the DLL version.
+///
+/// \return GFSDK_FaceWorks_OK if binary and header version does not match and the library has been
+/// initialized properly, or GFSDK_FaceWorks_Mismatch if versions does not match
+inline GFSDK_FaceWorks_Result GFSDK_FaceWorks_Init() {
+ return GFSDK_FaceWorks_Init_Internal(GFSDK_FaceWorks_HeaderVersion);
+}
+
+
+
+// =================================================================================
+// Building mesh data for SSS
+// =================================================================================
+
+/// Calculate size needed to store curvatures generated by GFSDK_FaceWorks_CalculateMeshCurvature
+/// Assuming they're not interleaved with any other vertex components
+///
+/// \param vertexCount [in] number of vertices
+///
+/// \return the size to store curvatures generated by GFSDK_FaceWorks_CalculateMeshCurvature, or zero if vertexCount is negative
+GFSDK_FACEWORKS_API size_t GFSDK_FACEWORKS_CALLCONV GFSDK_FaceWorks_CalculateCurvatureSizeBytes(int vertexCount);
+
+/// Generate per-vertex curvature for SSS.
+/// The positions and normals of the mesh are assumed to be in float3 format and the
+/// curvature is written out as a single float per vertex.
+/// Indices are assumed to be 32-bit ints.
+/// One or more smoothing passes can also be done on the calculated curvatures.
+///
+/// \param vertexCount [in] the vertex count
+/// \param pPositions [in] pointer to the positions (per-vertex)
+/// \param positionStrideBytes [in] distance, in bytes, between two positions in the pPosition buffer
+/// \param pNormals [in] pointer to the normals (per-vertex)
+/// \param normalStrideBytes [in] distance, in bytes, between two normals in the pNormal buffer
+/// \param indexCount [in] the index count
+/// \param pIndices [in] pointer to the indices buffer
+/// \param smoothingPassCount [in] number of smoothing passes applied to the curvatures
+/// \param pCurvaturesOut [out] pointer to the curvatures buffer (written by this function)
+/// \param curvatureStrideBytes [in] distance, in bytes, between two curvatures in the pCurvaturesOut
+/// \param pErrorBlobOut [in] buffer the error blob, where errors are stored.
+/// Error messages will be stored in the error blob, if one is given;
+/// if error messages are generated, use GFSDK_FaceWorks_FreeErrorBlob()
+/// to free the storage.
+/// The given allocator will be used to allocate temporary storage for
+/// working data, if provided; if not, the standard CRT allocator will
+/// be used.
+///
+/// \return GFSDK_FaceWorks_OK if parameters are correct
+/// GFSDK_FaceWorks_InvalidArgument if pConfig contains invalid values
+GFSDK_FACEWORKS_API GFSDK_FaceWorks_Result GFSDK_FACEWORKS_CALLCONV GFSDK_FaceWorks_CalculateMeshCurvature(
+ int vertexCount,
+ const void * pPositions,
+ int positionStrideBytes,
+ const void * pNormals,
+ int normalStrideBytes,
+ int indexCount,
+ const int * pIndices,
+ int smoothingPassCount,
+ void * pCurvaturesOut,
+ int curvatureStrideBytes,
+ GFSDK_FaceWorks_ErrorBlob * pErrorBlobOut,
+ gfsdk_new_delete_t * pAllocator);
+
+/// Calculate average UV scale.
+/// The positions and UVs of the mesh are assumed to be in float3 and float2 format,
+/// respectively.
+/// Indices are assumed to be 32-bit ints.
+///
+/// \param vertexCount [in] the vertex count
+/// \param pPositions [in] pointer to the positions (per-vertex)
+/// \param positionStrideBytes [in] distance, in bytes, between two positions in the pPosition buffer
+/// \param pUVs [in] pointer to the UV coordinates (per-vertex)
+/// \param uvStrideBytes [in] distance, in bytes, between two UV coordinates in the pUVs buffer
+/// \param indexCount [in] the index count
+/// \param pIndices [in] pointer to the indices buffer
+/// \param pAverageUVScaleOut [out] pointer to a float where the average UV scale will be stored
+/// \param pErrorBlobOut [in] buffer the error blob, where errors are stored.
+/// Error messages will be stored in the error blob, if one is given;
+/// if error messages are generated, use GFSDK_FaceWorks_FreeErrorBlob()
+/// to free the storage.
+/// The given allocator will be used to allocate temporary storage for
+/// working data, if provided; if not, the standard CRT allocator will
+/// be used.
+///
+/// \return GFSDK_FaceWorks_OK if parameters are correct
+/// GFSDK_FaceWorks_InvalidArgument if pConfig contains invalid values
+GFSDK_FACEWORKS_API GFSDK_FaceWorks_Result GFSDK_FACEWORKS_CALLCONV GFSDK_FaceWorks_CalculateMeshUVScale(
+ int vertexCount,
+ const void * pPositions,
+ int positionStrideBytes,
+ const void * pUVs,
+ int uvStrideBytes,
+ int indexCount,
+ const int * pIndices,
+ float * pAverageUVScaleOut,
+ GFSDK_FaceWorks_ErrorBlob * pErrorBlobOut);
+
+
+
+// =================================================================================
+// Building lookup textures for SSS
+// =================================================================================
+
+/// \brief Parameters for building curvature lookup texture (LUT) for SSS.
+typedef struct
+{
+ float m_diffusionRadius; ///< Diffusion radius, in world units (= 2.7mm for human skin)
+ int m_texWidth; ///< Width of curvature LUT (typically 512)
+ int m_texHeight; ///< Height of curvature LUT (typically 512)
+ float m_curvatureRadiusMin; ///< Min radius of curvature used to build the LUT (typically ~0.1 cm min)
+ float m_curvatureRadiusMax; ///< Max radius of curvature used to build the LUT (typically ~10.0 cm max)
+} GFSDK_FaceWorks_CurvatureLUTConfig;
+
+/// Calculate size needed to store pixels of texture generated by GFSDK_FaceWorks_GenerateCurvatureLUT.
+///
+/// \param pConfig [in] the parameters for building curvature lookup texture for SSS
+///
+/// \return the size needed to store pixels of texture generated by
+/// GFSDK_FaceWorks_GenerateCurvatureLUT
+GFSDK_FACEWORKS_API size_t GFSDK_FACEWORKS_CALLCONV GFSDK_FaceWorks_CalculateCurvatureLUTSizeBytes(
+ const GFSDK_FaceWorks_CurvatureLUTConfig * pConfig);
+
+/// Generate curvature lookup texture for SSS shaders.
+/// The image is stored in RGBA8 format to the given pointer, in left-to-right, top-to-bottom
+/// order. The curvature LUT is in linear color space.
+///
+/// \param pConfig [in] the parameters for building curvature lookup texture for SSS
+/// \param pCurvatureLUTOut [out] buffer where the curvature LUT is stored
+/// \param pErrorBlobOut [in] buffer the error blob, where errors are stored.
+/// Error messages will be stored in the error blob, if one is given;
+/// if error messages are generated, use GFSDK_FaceWorks_FreeErrorBlob()
+/// to free the storage.
+/// The given allocator will be used to allocate temporary storage for
+/// working data, if provided; if not, the standard CRT allocator will
+/// be used.
+///
+/// \return GFSDK_FaceWorks_OK if parameters are correct
+/// GFSDK_FaceWorks_InvalidArgument if pConfig contains invalid values
+GFSDK_FACEWORKS_API GFSDK_FaceWorks_Result GFSDK_FACEWORKS_CALLCONV GFSDK_FaceWorks_GenerateCurvatureLUT(
+ const GFSDK_FaceWorks_CurvatureLUTConfig * pConfig,
+ void * pCurvatureLUTOut,
+ GFSDK_FaceWorks_ErrorBlob * pErrorBlobOut);
+
+/// \brief Parameters for building shadow lookup texture (LUT) for SSS.
+typedef struct
+{
+ float m_diffusionRadius; ///< Diffusion radius, in world units (= 2.7mm for human skin)
+ int m_texWidth; ///< Width of curvature LUT (typically 512)
+ int m_texHeight; ///< Height of curvature LUT (typically 512)
+ float m_shadowWidthMin; ///< Min world-space penumbra width used to build the LUT (typically ~0.8 cm)
+ float m_shadowWidthMax; ///< Max world-space penumbra width used to build the LUT (typically ~10.0 cm)
+ float m_shadowSharpening; ///< Ratio by which output shadow is sharpened (adjust to taste; typically 3.0 to 10.0)
+} GFSDK_FaceWorks_ShadowLUTConfig;
+
+/// Calculate size needed to store pixels of texture generated by GFSDK_FaceWorks_GenerateShadowLUT.
+///
+/// \param pConfig [in] the parameters for building shadow lookup texture for SSS
+///
+/// \return the size needed to store pixels of texture generated by GFSDK_FaceWorks_GenerateShadowLUT
+GFSDK_FACEWORKS_API size_t GFSDK_FACEWORKS_CALLCONV GFSDK_FaceWorks_CalculateShadowLUTSizeBytes(
+ const GFSDK_FaceWorks_ShadowLUTConfig * pConfig);
+
+/// Generate shadow lookup texture for SSS shaders.
+/// The image is stored in RGBA8 format to the given pointer, in left-to-right, top-to-bottom
+/// order.
+/// The shadow LUT is in sRGB color space.
+///
+/// \param pConfig [in] the parameters for building shadow lookup texture for SSS
+/// \param pShadowLUTOut [out] buffer where the shadow LUT is stored
+/// \param pErrorBlobOut [in] buffer the error blob, where errors are stored.
+/// Error messages will be stored in the error blob, if one is given;
+/// if error messages are generated, use GFSDK_FaceWorks_FreeErrorBlob()
+/// to free the storage.
+/// The given allocator will be used to allocate temporary storage for
+/// working data, if provided; if not, the standard CRT allocator will
+/// be used.
+///
+/// \return GFSDK_FaceWorks_OK if parameters are correct
+/// GFSDK_FaceWorks_InvalidArgument if pConfig contains invalid values
+GFSDK_FACEWORKS_API GFSDK_FaceWorks_Result GFSDK_FACEWORKS_CALLCONV GFSDK_FaceWorks_GenerateShadowLUT(
+ const GFSDK_FaceWorks_ShadowLUTConfig * pConfig,
+ void * pShadowLUTOut,
+ GFSDK_FaceWorks_ErrorBlob * pErrorBlobOut);
+
+/// \brief Shared constant buffer
+/// Include this struct in your constant buffer; it provides data to the SSS and deep scatter APIs.
+/// This structure matches the corresponding struct in GFSDK_FaceWorks.hlsli.
+typedef struct
+{
+ gfsdk_float4 data[3]; ///< The opaque data used to communicate with shaders
+} GFSDK_FaceWorks_CBData;
+
+/// \brief Runtime config struct for SSS.
+typedef struct
+{
+ float m_diffusionRadius; ///< Diffusion radius, in world units (= 2.7mm for human skin)
+ float m_diffusionRadiusLUT; ///< Diffusion radius used to build the LUTs
+ float m_curvatureRadiusMinLUT; ///< Min radius of curvature used to build the LUT
+ float m_curvatureRadiusMaxLUT; ///< Max radius of curvature used to build the LUT
+ float m_shadowWidthMinLUT; ///< Min world-space penumbra width used to build the LUT
+ float m_shadowWidthMaxLUT; ///< Max world-space penumbra width used to build the LUT
+ float m_shadowFilterWidth; ///< World-space width of shadow filter
+ int m_normalMapSize; ///< Pixel size of normal map
+ float m_averageUVScale; ///< Average UV scale of the mesh, i.e. world-space size of UV unit square
+} GFSDK_FaceWorks_SSSConfig;
+
+/// Write constant buffer data for SSS, using specified configuration options.
+///
+/// \param pConfig [in] pointer to runtime config struct for SSS
+/// \param pCBDataOut [out] pointer to CBData struct in your constant buffer
+/// \param pErrorBlobOut [in] buffer the error blob, where errors are stored.
+/// Error messages will be stored in the error blob, if one is given;
+/// if error messages are generated, use GFSDK_FaceWorks_FreeErrorBlob()
+/// to free the storage.
+/// The given allocator will be used to allocate temporary storage for
+/// working data, if provided; if not, the standard CRT allocator will
+/// be used.
+///
+/// \return GFSDK_FaceWorks_OK if parameters are correct
+/// GFSDK_FaceWorks_InvalidArgument if pConfig contains invalid values
+GFSDK_FACEWORKS_API GFSDK_FaceWorks_Result GFSDK_FACEWORKS_CALLCONV GFSDK_FaceWorks_WriteCBDataForSSS(
+ const GFSDK_FaceWorks_SSSConfig * pConfig,
+ GFSDK_FaceWorks_CBData * pCBDataOut,
+ GFSDK_FaceWorks_ErrorBlob * pErrorBlobOut);
+
+/// Enum for projection types.
+typedef enum
+{
+ GFSDK_FaceWorks_NoProjection, ///< No Projection
+ GFSDK_FaceWorks_ParallelProjection, ///< Parallel projection
+ GFSDK_FaceWorks_PerspectiveProjection, ///< Perspective Projection
+} GFSDK_FaceWorks_ProjectionType;
+
+/// \brief Runtime config struct for deep scatter.
+/// \details Parameters m_shadow* are for shadow map thickness estimate: you only need to fill these in if
+/// you're using the FaceWorks helper functions forgetting the thickness. Set m_shadowProjType to
+/// GFSDK_FaceWorks_NoProjection if not using the helpers.
+typedef struct
+{
+ float m_radius; ///< Deep scatter radius, in world units
+ GFSDK_FaceWorks_ProjectionType
+ m_shadowProjType; ///< What type of projection this is
+ gfsdk_float4x4 m_shadowProjMatrix; ///< Shadow map projection matrix (row-vector convention)
+ float m_shadowFilterRadius; ///< Desired filter radius, in shadow texture UV space
+} GFSDK_FaceWorks_DeepScatterConfig;
+
+/// Write constant buffer data for deep scatter, using specified configuration options.
+///
+/// \param pConfig [in] pointer to runtime config struct for Deep Scatter
+/// \param pCBDataOut [out] pointer to CBData struct in your constant buffer
+/// \param pErrorBlobOut [in] buffer the error blob, where errors are stored.
+/// Error messages will be stored in the error blob, if one is given;
+/// if error messages are generated, use GFSDK_FaceWorks_FreeErrorBlob()
+/// to free the storage.
+/// The given allocator will be used to allocate temporary storage for
+/// working data, if provided; if not, the standard CRT allocator will
+/// be used.
+///
+/// \return GFSDK_FaceWorks_OK if parameters are correct
+/// GFSDK_FaceWorks_InvalidArgument if pConfig contains invalid values
+GFSDK_FACEWORKS_API GFSDK_FaceWorks_Result GFSDK_FACEWORKS_CALLCONV GFSDK_FaceWorks_WriteCBDataForDeepScatter(
+ const GFSDK_FaceWorks_DeepScatterConfig * pConfig,
+ GFSDK_FaceWorks_CBData * pCBDataOut,
+ GFSDK_FaceWorks_ErrorBlob * pErrorBlobOut);
+
+#pragma pack(pop)
+
+#endif // GFSDK_FACEWORKS_H
diff --git a/include/GFSDK_FaceWorks.hlsli b/include/GFSDK_FaceWorks.hlsli
new file mode 100644
index 0000000..3caba16
--- /dev/null
+++ b/include/GFSDK_FaceWorks.hlsli
@@ -0,0 +1,572 @@
+//----------------------------------------------------------------------------------
+// File: FaceWorks/include/GFSDK_FaceWorks.hlsli
+// SDK Version: v1.0
+// Site: http://developer.nvidia.com/
+//
+// Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// * Neither the name of NVIDIA CORPORATION nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//----------------------------------------------------------------------------------
+
+#ifndef GFSDK_FACEWORKS_HLSLI
+#define GFSDK_FACEWORKS_HLSLI
+
+// =================================================================================
+// Constant buffer data
+// =================================================================================
+
+/// Include this struct in your constant buffer; provides data to the SSS and deep scatter APIs
+/// (matches the corresponding struct in GFSDK_FaceWorks.h)
+struct GFSDK_FaceWorks_CBData
+{
+ float4 data[3];
+};
+
+
+
+// =================================================================================
+// Shader API for SSS
+// =================================================================================
+
+/// Calculate mip level at which to sample normal map, to get the blurred normal to pass to
+/// GFSDK_FaceWorks_EvaluateSSSDiffuseLight.
+///
+/// \param cbdata [in] the cbdata structure
+/// \param texNormal [in] the texture to use
+/// \param samp [in] the sampler to use
+/// \param uv [in] the UV to sample at
+///
+/// \return the mip level to sample at.
+float GFSDK_FaceWorks_CalculateMipLevelForBlurredNormal(
+ GFSDK_FaceWorks_CBData cbdata,
+ Texture2D texNormal,
+ SamplerState samp,
+ float2 uv);
+
+/// Calculate mip level at which to sample normal map, to get the blurred normal to pass to
+/// GFSDK_FaceWorks_EvaluateSSSDiffuseLight.
+///
+/// \param cbdata [in] the cbdata structure
+/// \param texNormal [in] the texture to use (float3)
+/// \param samp [in] the sampler to use
+/// \param uv [in] the UV to sample at
+///
+/// \return the mip level to sample at.
+float GFSDK_FaceWorks_CalculateMipLevelForBlurredNormal(
+ GFSDK_FaceWorks_CBData cbdata,
+ Texture2D<float3> texNormal,
+ SamplerState samp,
+ float2 uv);
+
+/// Calculate mip level at which to sample normal map, to get the blurred normal to pass to
+/// GFSDK_FaceWorks_EvaluateSSSDiffuseLight.
+///
+/// \param cbdata [in] the cbdata structure
+/// \param texNormal [in] the texture to use (float2)
+/// \param samp [in] the sampler to use
+/// \param uv [in] the UV to sample at
+///
+/// \return the mip level to sample at.
+float GFSDK_FaceWorks_CalculateMipLevelForBlurredNormal(
+ GFSDK_FaceWorks_CBData cbdata,
+ Texture2D<float2> texNormal,
+ SamplerState samp,
+ float2 uv);
+
+/// Evaluate SSS diffuse light for a single light source.
+///
+/// \param cbdata [in] the cbdata structure
+/// \param normalGeom [in] the geometric normal
+/// \param normalShade [in] the shading normal
+/// \param normalBlurred [in] the blurred shading normal
+/// \param vecToLight [in] the normalized vector toward light
+/// \param curvature [in] curvature of the surface being shaded (interpolated from precomputed
+/// per-vertex values)
+/// \param texCurvatureLUT [in] the texture containing curvature look up table
+/// \param ssBilinearClamp [in] the sampler state
+///
+/// \return the SSS lighting value, to be multiplied by the shadow color, diffuse color, and light color.
+float3 GFSDK_FaceWorks_EvaluateSSSDirectLight(
+ GFSDK_FaceWorks_CBData cbdata,
+ float3 normalGeom,
+ float3 normalShade,
+ float3 normalBlurred,
+ float3 vecToLight,
+ float curvature,
+ Texture2D texCurvatureLUT,
+ SamplerState ssBilinearClamp);
+
+/// Evaluate SSS shadow color for a single light source.
+///
+/// \param cbdata [in] the cbdata structure
+/// \param normalGeom [in] the geometric normal
+/// \param vecToLight [in] the normalized vector toward light
+/// \param shadow [in] wide shadow filter (0 = fully shadowed, 1 = fully lit).
+/// \param texShadowLUT [in] the texture containing curvature look up table
+/// \param ssBilinearClamp [in] the sampler state
+///
+/// \return the shadow color, including sharpened shadows and SSS light bleeding.
+float3 GFSDK_FaceWorks_EvaluateSSSShadow(
+ GFSDK_FaceWorks_CBData cbdata,
+ float3 normalGeom,
+ float3 vecToLight,
+ float shadow,
+ Texture2D texShadowLUT,
+ SamplerState ssBilinearClamp);
+
+/// Sharpen an input shadow value to approximate the output shadow after mapping through the
+/// shadow LUT. This sharpened shadow can be used for specular or other lighting components.
+///
+/// \param shadow shadow value (0 = full shadow, 1 = full light)
+/// \param shadowSharpening sharpening factor (same as m_shadowSharpening in GFSDK_FaceWorks_LUTConfig)
+///
+/// \return the sharpened shadow value
+float GFSDK_FaceWorks_SharpenShadow(
+ float shadow,
+ float shadowSharpening);
+
+/// Calculate three normals at which to sample diffuse ambient light (such as SH light or
+/// a preconvolved cubemap) for SSS ambient light.
+///
+/// \param normalShade [in] the shading normal
+/// \param normalBlurred [in] the blurred shading normal
+/// \param o_normalAmbient0 [out] first normal at which to sample diffuse ambient light
+/// \param o_normalAmbient1 [out] second normal at which to sample diffuse ambient light
+/// \param o_normalAmbient2 [out] third normal at which to sample diffuse ambient light
+void GFSDK_FaceWorks_CalculateNormalsForAmbientLight(
+ float3 normalShade,
+ float3 normalBlurred,
+ out float3 o_normalAmbient0,
+ out float3 o_normalAmbient1,
+ out float3 o_normalAmbient2);
+
+/// Evaluate SSS ambient light.
+/// \param rgbAmbient0 [in] ambient light evaluated at the first normal calculated by GFSDK_FaceWorks_CalculateNormalsForAmbientLight.
+/// \param rgbAmbient1 [in] ambient light evaluated at the first normal calculated by GFSDK_FaceWorks_CalculateNormalsForAmbientLight.
+/// \param rgbAmbient2 [in] ambient light evaluated at the first normal calculated by GFSDK_FaceWorks_CalculateNormalsForAmbientLight.
+///
+/// \return the SSS lighting value, to be multiplied by the diffuse color.
+float3 GFSDK_FaceWorks_EvaluateSSSAmbientLight(
+ float3 rgbAmbient0,
+ float3 rgbAmbient1,
+ float3 rgbAmbient2);
+
+
+
+// =================================================================================
+// Shader API for deep scatter
+// =================================================================================
+
+/// Estimate thickness from parallel shadow map using 8-tap Poisson disc filter
+///
+/// \param cbdata [in] the cbdata structure
+/// \param texDepth [in] the shadow map (as a depth texture)
+/// \param ss [in] the sampler state
+/// \param uvzShadow [in] and the position in [0, 1]-space at which to sample the shadow map.
+///
+/// \return the estimated thickness value
+float GFSDK_FaceWorks_EstimateThicknessFromParallelShadowPoisson8(
+ GFSDK_FaceWorks_CBData cbdata,
+ Texture2D<float> texDepth,
+ SamplerState ss,
+ float3 uvzShadow);
+
+/// Estimate thickness from perspective shadow map using 8-tap Poisson disc filter
+///
+/// \param cbdata [in] the cbdata structure
+/// \param texDepth [in] the shadow map (as a depth texture)
+/// \param ss [in] the sampler state
+/// \param uvzShadow [in] and the position in [0, 1]-space at which to sample the shadow map.
+///
+/// \return the estimated thickness value
+float GFSDK_FaceWorks_EstimateThicknessFromPerspectiveShadowPoisson8(
+ GFSDK_FaceWorks_CBData cbdata,
+ Texture2D<float> texDepth,
+ SamplerState ss,
+ float3 uvzShadow);
+
+/// Estimate thickness from parallel shadow map using 32-tap Poisson disc filter
+///
+/// \param cbdata [in] the cbdata structure
+/// \param texDepth [in] the shadow map (as a depth texture)
+/// \param ss [in] the sampler state
+/// \param uvzShadow [in] and the position in [0, 1]-space at which to sample the shadow map.
+///
+/// \return the estimated thickness value
+float GFSDK_FaceWorks_EstimateThicknessFromParallelShadowPoisson32(
+ GFSDK_FaceWorks_CBData cbdata,
+ Texture2D<float> texDepth,
+ SamplerState ss,
+ float3 uvzShadow);
+
+/// Estimate thickness from perspective shadow map using 32-tap Poisson disc filter
+///
+/// \param cbdata [in] the cbdata structure
+/// \param texDepth [in] the shadow map (as a depth texture)
+/// \param ss [in] the sampler state
+/// \param uvzShadow [in] and the position in [0, 1]-space at which to sample the shadow map.
+///
+/// \return the estimated thickness value
+float GFSDK_FaceWorks_EstimateThicknessFromPerspectiveShadowPoisson32(
+ GFSDK_FaceWorks_CBData cbdata,
+ Texture2D<float> texDepth,
+ SamplerState ss,
+ float3 uvzShadow);
+
+/// Evaluate deep scattered light for a single light source.
+///
+/// \param cbdata [in] the cbdata structure
+/// \param normalBlurred [in] the blurred shading normal
+/// \param vecToLight [in] the normalized vector toward light
+/// \param thickness [in] the object thickness estimated from shadow map
+///
+/// \return the scalar deep scatter lighting value, to be multiplied by the deep scatter
+/// color, diffuse color and light color.
+float GFSDK_FaceWorks_EvaluateDeepScatterDirectLight(
+ GFSDK_FaceWorks_CBData cbdata,
+ float3 normalBlurred,
+ float3 vecToLight,
+ float thickness);
+
+
+
+// ======================================================================================
+// Implementation
+// ======================================================================================
+
+// Structure used to unpack the CB data
+struct nvsf_CBData
+{
+ // SSS constants
+ float2 nvsf_CurvatureScaleBias;
+ float2 nvsf_ShadowScaleBias;
+ float nvsf_MinLevelForBlurredNormal;
+
+ // Deep scatter constants
+ float nvsf_DeepScatterFalloff;
+ float nvsf_ShadowFilterRadius;
+ float nvsf_DecodeDepthScale, nvsf_DecodeDepthBias;
+};
+
+nvsf_CBData nvsf_UnpackCBData(GFSDK_FaceWorks_CBData nvsf_opaqueData)
+{
+ nvsf_CBData nvsf_out = (nvsf_CBData)0;
+ nvsf_out.nvsf_CurvatureScaleBias = nvsf_opaqueData.data[0].xy;
+ nvsf_out.nvsf_ShadowScaleBias = nvsf_opaqueData.data[0].zw;
+ nvsf_out.nvsf_MinLevelForBlurredNormal = nvsf_opaqueData.data[1].x;
+ nvsf_out.nvsf_DeepScatterFalloff = nvsf_opaqueData.data[1].y;
+ nvsf_out.nvsf_ShadowFilterRadius = nvsf_opaqueData.data[1].z;
+ nvsf_out.nvsf_DecodeDepthScale = nvsf_opaqueData.data[1].w;
+ nvsf_out.nvsf_DecodeDepthBias = nvsf_opaqueData.data[2].x;
+ return nvsf_out;
+}
+
+
+
+// ======================================================================================
+// Shader API for SSS
+// ======================================================================================
+
+float GFSDK_FaceWorks_CalculateMipLevelForBlurredNormal(
+ GFSDK_FaceWorks_CBData nvsf_opaqueData,
+ Texture2D nvsf_texNormal,
+ SamplerState nvsf_ss,
+ float2 nvsf_uv)
+{
+ nvsf_CBData nvsf_cb = nvsf_UnpackCBData(nvsf_opaqueData);
+ return max(nvsf_texNormal.CalculateLevelOfDetail(nvsf_ss, nvsf_uv),
+ nvsf_cb.nvsf_MinLevelForBlurredNormal);
+}
+float GFSDK_FaceWorks_CalculateMipLevelForBlurredNormal(
+ GFSDK_FaceWorks_CBData nvsf_opaqueData,
+ Texture2D<float3> nvsf_texNormal,
+ SamplerState nvsf_ss,
+ float2 nvsf_uv)
+{
+ nvsf_CBData nvsf_cb = nvsf_UnpackCBData(nvsf_opaqueData);
+ return max(nvsf_texNormal.CalculateLevelOfDetail(nvsf_ss, nvsf_uv),
+ nvsf_cb.nvsf_MinLevelForBlurredNormal);
+}
+float GFSDK_FaceWorks_CalculateMipLevelForBlurredNormal(
+ GFSDK_FaceWorks_CBData nvsf_opaqueData,
+ Texture2D<float2> nvsf_texNormal,
+ SamplerState nvsf_ss,
+ float2 nvsf_uv)
+{
+ nvsf_CBData nvsf_cb = nvsf_UnpackCBData(nvsf_opaqueData);
+ return max(nvsf_texNormal.CalculateLevelOfDetail(nvsf_ss, nvsf_uv),
+ nvsf_cb.nvsf_MinLevelForBlurredNormal);
+}
+
+float3 GFSDK_FaceWorks_EvaluateSSSDirectLight(
+ GFSDK_FaceWorks_CBData nvsf_opaqueData,
+ float3 nvsf_normalGeom,
+ float3 nvsf_normalShade,
+ float3 nvsf_normalBlurred,
+ float3 nvsf_vecToLight,
+ float nvsf_curvature,
+ Texture2D nvsf_texCurvatureLUT,
+ SamplerState nvsf_ss)
+{
+ nvsf_CBData nvsf_cb = nvsf_UnpackCBData(nvsf_opaqueData);
+
+ // Curvature-based scattering
+ float nvsf_NdotLBlurredUnclamped = dot(nvsf_normalBlurred, nvsf_vecToLight);
+ float nvsf_curvatureScaled = nvsf_curvature * nvsf_cb.nvsf_CurvatureScaleBias.x + nvsf_cb.nvsf_CurvatureScaleBias.y;
+ float2 nvsf_uvCurvatureLUT = { nvsf_NdotLBlurredUnclamped * 0.5 + 0.5, nvsf_curvatureScaled, };
+ float3 nvsf_rgbCurvature = nvsf_texCurvatureLUT.Sample(nvsf_ss, nvsf_uvCurvatureLUT).rgb * 0.5 - 0.25;
+
+ // Normal map scattering using separate normals for R, G, B; here, G and B
+ // normals are generated by lerping between the specular and R normals.
+ // The lerp factor to generate the G and B normals is increased near the light/dark edge,
+ // to try to prevent bumps from showing up as too blue.
+ // This will be more complex when arbitrary diffusion profiles are supported.
+ float3 nvsf_normalSmoothFactor = saturate(1.0 - nvsf_NdotLBlurredUnclamped);
+ nvsf_normalSmoothFactor *= nvsf_normalSmoothFactor;
+ float3 nvsf_normalShadeG = normalize(lerp(nvsf_normalShade, nvsf_normalBlurred, 0.3 + 0.7 * nvsf_normalSmoothFactor));
+ float3 nvsf_normalShadeB = normalize(lerp(nvsf_normalShade, nvsf_normalBlurred, nvsf_normalSmoothFactor));
+ float nvsf_NdotLShadeG = saturate(dot(nvsf_normalShadeG, nvsf_vecToLight));
+ float nvsf_NdotLShadeB = saturate(dot(nvsf_normalShadeB, nvsf_vecToLight));
+ float3 nvsf_rgbNdotL = float3(saturate(nvsf_NdotLBlurredUnclamped), nvsf_NdotLShadeG, nvsf_NdotLShadeB);
+
+ return saturate(nvsf_rgbCurvature + nvsf_rgbNdotL);
+}
+
+float3 GFSDK_FaceWorks_EvaluateSSSShadow(
+ GFSDK_FaceWorks_CBData nvsf_opaqueData,
+ float3 nvsf_normalGeom,
+ float3 nvsf_vecToLight,
+ float nvsf_shadow,
+ Texture2D nvsf_texShadowLUT,
+ SamplerState nvsf_ss)
+{
+ nvsf_CBData nvsf_cb = nvsf_UnpackCBData(nvsf_opaqueData);
+
+ // Shadow penumbra scattering
+ float nvsf_NdotLGeom = saturate(dot(nvsf_normalGeom, nvsf_vecToLight));
+ float2 nvsf_uvShadowLUT =
+ {
+ nvsf_shadow,
+ nvsf_NdotLGeom * nvsf_cb.nvsf_ShadowScaleBias.x + nvsf_cb.nvsf_ShadowScaleBias.y,
+ };
+ return nvsf_texShadowLUT.Sample(nvsf_ss, nvsf_uvShadowLUT).rgb;
+}
+
+float GFSDK_FaceWorks_SharpenShadow(
+ float nvsf_shadow,
+ float nvsf_shadowSharpening)
+{
+ // Use smoothstep to approximate the transfer function of a disc or Gaussian shadow filter
+ float nvsf_scale = nvsf_shadowSharpening * 0.9;
+ float nvsf_bias = -0.5 * nvsf_scale + 0.5;
+ return smoothstep(0, 1, nvsf_shadow * nvsf_scale + nvsf_bias);
+}
+
+void GFSDK_FaceWorks_CalculateNormalsForAmbientLight(
+ float3 nvsf_normalShade,
+ float3 nvsf_normalBlurred,
+ out float3 nvsf_o_normalAmbient0,
+ out float3 nvsf_o_normalAmbient1,
+ out float3 nvsf_o_normalAmbient2)
+{
+ // Same normals as for direct light, but no NdotL factor involved.
+ // This will be more complex when arbitrary diffusion profiles are supported.
+ nvsf_o_normalAmbient0 = nvsf_normalBlurred;
+ nvsf_o_normalAmbient1 = normalize(lerp(nvsf_normalShade, nvsf_normalBlurred, 0.3));
+ nvsf_o_normalAmbient2 = nvsf_normalShade;
+}
+
+float3 GFSDK_FaceWorks_EvaluateSSSAmbientLight(
+ float3 nvsf_rgbAmbient0,
+ float3 nvsf_rgbAmbient1,
+ float3 nvsf_rgbAmbient2)
+{
+ // This will be more complex when arbitrary diffusion profiles are supported.
+ float3 nvsf_result;
+ nvsf_result.r = nvsf_rgbAmbient0.r;
+ nvsf_result.g = nvsf_rgbAmbient1.g;
+ nvsf_result.b = nvsf_rgbAmbient2.b;
+ return nvsf_result;
+}
+
+
+
+// ======================================================================================
+// Shader API for deep scatter
+// ======================================================================================
+
+// Poisson disks generated with http://www.coderhaus.com/?p=11
+
+static const float2 nvsf_Poisson8[] =
+{
+ { -0.7494944f, 0.1827986f, },
+ { -0.8572887f, -0.4169083f, },
+ { -0.1087135f, -0.05238153f, },
+ { 0.1045462f, 0.9657645f, },
+ { -0.0135659f, -0.698451f, },
+ { -0.4942278f, 0.7898396f, },
+ { 0.7970678f, -0.4682421f, },
+ { 0.8084122f, 0.533884f },
+};
+
+static const float2 nvsf_Poisson32[] =
+{
+ { -0.975402, -0.0711386 },
+ { -0.920347, -0.41142 },
+ { -0.883908, 0.217872 },
+ { -0.884518, 0.568041 },
+ { -0.811945, 0.90521 },
+ { -0.792474, -0.779962 },
+ { -0.614856, 0.386578 },
+ { -0.580859, -0.208777 },
+ { -0.53795, 0.716666 },
+ { -0.515427, 0.0899991 },
+ { -0.454634, -0.707938 },
+ { -0.420942, 0.991272 },
+ { -0.261147, 0.588488 },
+ { -0.211219, 0.114841 },
+ { -0.146336, -0.259194 },
+ { -0.139439, -0.888668 },
+ { 0.0116886, 0.326395 },
+ { 0.0380566, 0.625477 },
+ { 0.0625935, -0.50853 },
+ { 0.125584, 0.0469069 },
+ { 0.169469, -0.997253 },
+ { 0.320597, 0.291055 },
+ { 0.359172, -0.633717 },
+ { 0.435713, -0.250832 },
+ { 0.507797, -0.916562 },
+ { 0.545763, 0.730216 },
+ { 0.56859, 0.11655 },
+ { 0.743156, -0.505173 },
+ { 0.736442, -0.189734 },
+ { 0.843562, 0.357036 },
+ { 0.865413, 0.763726 },
+ { 0.872005, -0.927 },
+};
+
+float nvsf_LinearizePerspectiveDepth(nvsf_CBData nvsf_cb, float nvsf_depth)
+{
+ return 1.0 / (nvsf_depth * nvsf_cb.nvsf_DecodeDepthScale + nvsf_cb.nvsf_DecodeDepthBias);
+}
+
+float GFSDK_FaceWorks_EstimateThicknessFromParallelShadowPoisson8(
+ GFSDK_FaceWorks_CBData nvsf_opaqueData,
+ Texture2D<float> nvsf_texDepth,
+ SamplerState nvsf_ss,
+ float3 nvsf_uvzShadow)
+{
+ nvsf_CBData nvsf_cb = nvsf_UnpackCBData(nvsf_opaqueData);
+
+ float nvsf_sampleSum = 0.0;
+ [unroll] for (int i = 0; i < 8; ++i)
+ {
+ float2 nvsf_uvDelta = nvsf_Poisson8[i] * nvsf_cb.nvsf_ShadowFilterRadius;
+ float2 nvsf_uvSample = nvsf_uvzShadow.xy + nvsf_uvDelta;
+ float nvsf_zShadowMap = nvsf_texDepth.Sample(nvsf_ss, nvsf_uvSample);
+ nvsf_sampleSum += max(0, nvsf_uvzShadow.z - nvsf_zShadowMap);
+ }
+
+ return nvsf_cb.nvsf_DecodeDepthScale * nvsf_sampleSum * (1.0 / 8.0);
+}
+
+float GFSDK_FaceWorks_EstimateThicknessFromPerspectiveShadowPoisson8(
+ GFSDK_FaceWorks_CBData nvsf_opaqueData,
+ Texture2D<float> nvsf_texDepth,
+ SamplerState nvsf_ss,
+ float3 nvsf_uvzShadow)
+{
+ nvsf_CBData nvsf_cb = nvsf_UnpackCBData(nvsf_opaqueData);
+
+ float nvsf_sampleSum = 0.0;
+ float nvsf_linearDepth = nvsf_LinearizePerspectiveDepth(nvsf_cb, nvsf_uvzShadow.z);
+ [unroll] for (int i = 0; i < 8; ++i)
+ {
+ float2 nvsf_uvDelta = nvsf_Poisson8[i] * nvsf_cb.nvsf_ShadowFilterRadius;
+ float2 nvsf_uvSample = nvsf_uvzShadow.xy + nvsf_uvDelta;
+ float nvsf_zShadowMap = nvsf_texDepth.Sample(nvsf_ss, nvsf_uvSample);
+ nvsf_sampleSum += max(0, nvsf_linearDepth - nvsf_LinearizePerspectiveDepth(nvsf_cb, nvsf_zShadowMap));
+ }
+
+ return nvsf_sampleSum * (1.0 / 8.0);
+}
+
+float GFSDK_FaceWorks_EstimateThicknessFromParallelShadowPoisson32(
+ GFSDK_FaceWorks_CBData nvsf_opaqueData,
+ Texture2D<float> nvsf_texDepth,
+ SamplerState nvsf_ss,
+ float3 nvsf_uvzShadow)
+{
+ nvsf_CBData nvsf_cb = nvsf_UnpackCBData(nvsf_opaqueData);
+
+ float nvsf_sampleSum = 0.0;
+ [unroll] for (int i = 0; i < 32; ++i)
+ {
+ float2 nvsf_uvDelta = nvsf_Poisson32[i] * nvsf_cb.nvsf_ShadowFilterRadius;
+ float2 nvsf_uvSample = nvsf_uvzShadow.xy + nvsf_uvDelta;
+ float nvsf_zShadowMap = nvsf_texDepth.Sample(nvsf_ss, nvsf_uvSample);
+ nvsf_sampleSum += max(0, nvsf_uvzShadow.z - nvsf_zShadowMap);
+ }
+
+ return nvsf_cb.nvsf_DecodeDepthScale * nvsf_sampleSum * (1.0 / 32.0);
+}
+
+float GFSDK_FaceWorks_EstimateThicknessFromPerspectiveShadowPoisson32(
+ GFSDK_FaceWorks_CBData nvsf_opaqueData,
+ Texture2D<float> nvsf_texDepth,
+ SamplerState nvsf_ss,
+ float3 nvsf_uvzShadow)
+{
+ nvsf_CBData nvsf_cb = nvsf_UnpackCBData(nvsf_opaqueData);
+
+ float nvsf_sampleSum = 0.0;
+ float nvsf_linearDepth = nvsf_LinearizePerspectiveDepth(nvsf_cb, nvsf_uvzShadow.z);
+ [unroll] for (int i = 0; i < 32; ++i)
+ {
+ float2 nvsf_uvDelta = nvsf_Poisson32[i] * nvsf_cb.nvsf_ShadowFilterRadius;
+ float2 nvsf_uvSample = nvsf_uvzShadow.xy + nvsf_uvDelta;
+ float nvsf_zShadowMap = nvsf_texDepth.Sample(nvsf_ss, nvsf_uvSample);
+ nvsf_sampleSum += max(0, nvsf_linearDepth - nvsf_LinearizePerspectiveDepth(nvsf_cb, nvsf_zShadowMap));
+ }
+
+ return nvsf_sampleSum * (1.0 / 32.0);
+}
+
+float GFSDK_FaceWorks_EvaluateDeepScatterDirectLight(
+ GFSDK_FaceWorks_CBData nvsf_opaqueData,
+ float3 nvsf_normalBlurred,
+ float3 nvsf_vecToLight,
+ float nvsf_thickness)
+{
+ nvsf_CBData nvsf_cb = nvsf_UnpackCBData(nvsf_opaqueData);
+
+ float nvsf_transmittance = exp2(nvsf_cb.nvsf_DeepScatterFalloff * nvsf_thickness * nvsf_thickness);
+ float nvsf_minusNDotL = -dot(nvsf_normalBlurred, nvsf_vecToLight);
+ return nvsf_transmittance * saturate(nvsf_minusNDotL + 0.3);
+}
+
+#endif // GFSDK_FACEWORKS_HLSLI