aboutsummaryrefslogtreecommitdiff
path: root/samples/d3d11
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 /samples/d3d11
downloadfaceworks-cd6e0492903f8a9eb5efa14263d7d9ab092517de.tar.xz
faceworks-cd6e0492903f8a9eb5efa14263d7d9ab092517de.zip
FaceWorks 1.0
Diffstat (limited to 'samples/d3d11')
-rw-r--r--samples/d3d11/sample_d3d11.cpp1545
-rw-r--r--samples/d3d11/scenes.cpp1079
-rw-r--r--samples/d3d11/scenes.h299
-rw-r--r--samples/d3d11/shader.cpp861
-rw-r--r--samples/d3d11/shader.h219
-rw-r--r--samples/d3d11/shaders/common.hlsli97
-rw-r--r--samples/d3d11/shaders/copy_ps.hlsl48
-rw-r--r--samples/d3d11/shaders/create_vsm_ps.hlsl43
-rw-r--r--samples/d3d11/shaders/curvature_ps.hlsl42
-rw-r--r--samples/d3d11/shaders/curvature_vs.hlsl49
-rw-r--r--samples/d3d11/shaders/eye.hlsli132
-rw-r--r--samples/d3d11/shaders/gaussian_ps.hlsl91
-rw-r--r--samples/d3d11/shaders/hair_ps.hlsl82
-rw-r--r--samples/d3d11/shaders/lighting.hlsli293
-rw-r--r--samples/d3d11/shaders/resources.h75
-rw-r--r--samples/d3d11/shaders/screen_vs.hlsl45
-rw-r--r--samples/d3d11/shaders/shadow_vs.hlsl53
-rw-r--r--samples/d3d11/shaders/skin.hlsli108
-rw-r--r--samples/d3d11/shaders/skybox_ps.hlsl43
-rw-r--r--samples/d3d11/shaders/skybox_vs.hlsl52
-rw-r--r--samples/d3d11/shaders/tess.hlsli46
-rw-r--r--samples/d3d11/shaders/tess_ds.hlsl75
-rw-r--r--samples/d3d11/shaders/tess_hs.hlsl124
-rw-r--r--samples/d3d11/shaders/tess_vs.hlsl43
-rw-r--r--samples/d3d11/shaders/thickness_ps.hlsl62
-rw-r--r--samples/d3d11/shaders/tonemap.hlsli62
-rw-r--r--samples/d3d11/shaders/world_vs.hlsl48
-rw-r--r--samples/d3d11/util.cpp1451
-rw-r--r--samples/d3d11/util.h262
29 files changed, 7429 insertions, 0 deletions
diff --git a/samples/d3d11/sample_d3d11.cpp b/samples/d3d11/sample_d3d11.cpp
new file mode 100644
index 0000000..db86536
--- /dev/null
+++ b/samples/d3d11/sample_d3d11.cpp
@@ -0,0 +1,1545 @@
+// This code contains NVIDIA Confidential Information and is disclosed
+// under the Mutual Non-Disclosure Agreement.
+//
+// Notice
+// ALL NVIDIA DESIGN SPECIFICATIONS AND CODE ("MATERIALS") ARE PROVIDED "AS IS" NVIDIA MAKES
+// NO REPRESENTATIONS, WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. No third party distribution is allowed unless
+// expressly authorized by NVIDIA. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright � 2014 NVIDIA Corporation. All rights reserved.
+//
+// NVIDIA Corporation and its licensors retain all intellectual property and proprietary
+// rights in and to this software and related documentation and any modifications thereto.
+// Any use, reproduction, disclosure or distribution of this software and related
+// documentation without an express license agreement from NVIDIA Corporation is
+// strictly prohibited.
+//
+
+#include <cstdarg>
+#include <cstdio>
+#include <limits>
+#include <algorithm>
+
+#include <DirectXMath.h>
+
+#include <DXUT/Core/DXUT.h>
+#include <DXUT/Optional/DXUTcamera.h>
+#include <DXUT/Optional/DXUTgui.h>
+#include <DXUT/Optional/SDKmisc.h>
+
+#include <GFSDK_FaceWorks.h>
+
+#include "util.h"
+#include "scenes.h"
+#include "shader.h"
+
+
+using namespace DirectX;
+using namespace std;
+
+// DXUT objects
+
+CDXUTDialogResourceManager g_DialogResourceManager; // manager for shared resources of dialogs
+CDXUTDialog g_HUD; // dialog for standard controls
+CDXUTTextHelper * g_pTxtHelper = nullptr;
+
+bool g_ShowHelp = false;
+bool g_ShowGUI = true;
+bool g_ShowText = true;
+bool g_bWireframe = false;
+bool g_bShowPerf = true;
+bool g_bCopyPerfToClipboard = false;
+bool g_bTessellation = true;
+
+// DXUT callbacks
+
+HRESULT InitScene();
+void CALLBACK OnFrameMove(double fTime, float fElapsedTime, void * pUserContext);
+void CALLBACK OnD3D11FrameRender(ID3D11Device * pd3dDevice, ID3D11DeviceContext * pd3dContext, double fTime, float fElapsedTime, void * pUserContext);
+
+bool CALLBACK IsD3D11DeviceAcceptable(const CD3D11EnumAdapterInfo * AdapterInfo, UINT Output, const CD3D11EnumDeviceInfo * DeviceInfo, DXGI_FORMAT BackBufferFormat, bool bWindowed, void * pUserContext);
+bool CALLBACK ModifyDeviceSettings(DXUTDeviceSettings * pDeviceSettings, void * pUserContext);
+HRESULT CALLBACK OnD3D11CreateDevice(ID3D11Device * pd3dDevice, const DXGI_SURFACE_DESC * pBackBufferSurfaceDesc, void * pUserContext);
+HRESULT CALLBACK OnD3D11ResizedSwapChain(ID3D11Device * pd3dDevice, IDXGISwapChain * pSwapChain, const DXGI_SURFACE_DESC * pBackBufferSurfaceDesc, void * pUserContext);
+void CALLBACK OnD3D11ReleasingSwapChain(void * pUserContext);
+void CALLBACK OnD3D11DestroyDevice(void * pUserContext);
+
+void InitUI();
+void CALLBACK OnGUIEvent(UINT nEvent, int nControlID, CDXUTControl * pControl, void * pUserContext);
+void UpdateSliders();
+void RenderText();
+LRESULT CALLBACK MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool * pbNoFurtherProcessing, void * pUserContext);
+void CALLBACK OnKeyboard(UINT nChar, bool bKeyDown, bool bAltDown, void * pUserContext);
+
+
+
+int WINAPI wWinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPWSTR /*lpszCmdLine*/, int /*nCmdShow*/)
+{
+ // Enable run-time memory check for debug builds.
+
+#if defined(_DEBUG)
+ _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
+#endif
+
+ // Set up DXUT callbacks
+
+ DXUTSetCallbackFrameMove(&OnFrameMove);
+ DXUTSetCallbackD3D11FrameRender(&OnD3D11FrameRender);
+
+ DXUTSetCallbackD3D11DeviceAcceptable(&IsD3D11DeviceAcceptable);
+ DXUTSetCallbackDeviceChanging(&ModifyDeviceSettings);
+ DXUTSetCallbackD3D11DeviceCreated(&OnD3D11CreateDevice);
+ DXUTSetCallbackD3D11SwapChainResized(&OnD3D11ResizedSwapChain);
+ DXUTSetCallbackD3D11SwapChainReleasing(&OnD3D11ReleasingSwapChain);
+ DXUTSetCallbackD3D11DeviceDestroyed(&OnD3D11DestroyDevice);
+
+ DXUTSetCallbackMsgProc(&MsgProc);
+ DXUTSetCallbackKeyboard(&OnKeyboard);
+
+ InitUI();
+
+ DXUTInit(
+ true, // Parse command line
+ true); // Show msgboxes on error
+ DXUTSetCursorSettings(
+ true, // Show cursor when fullscreen
+ true); // Clip cursor when fullscreen
+ DXUTCreateWindow(L"GeForce SDK FaceWorks D3D11 Test");
+ DXUTCreateDevice(
+ D3D_FEATURE_LEVEL_11_0,
+ true, // Windowed mode
+ 1920,
+ 1080);
+
+ DXUTMainLoop();
+ return DXUTGetExitCode();
+}
+
+
+
+// Rendering methods
+
+enum RM
+{
+ RM_None,
+ RM_SSS,
+ RM_SSSAndDeep,
+ RM_ViewCurvature,
+ RM_ViewThickness,
+
+ RM_Max
+};
+
+RM g_renderMethod = RM_SSSAndDeep;
+
+
+
+// Viewable buffers
+
+enum VIEWBUF
+{
+ VIEWBUF_None,
+ VIEWBUF_ShadowMap,
+
+ VIEWBUF_Max
+};
+
+VIEWBUF g_viewbuf = VIEWBUF_None;
+static const XMFLOAT4 s_rectViewBuffer(10, 50, 512, 512);
+
+
+
+// Scene resources
+
+const float g_FOV = 0.5f; // vertical fov, radians
+
+CSceneDigitalIra g_sceneDigitalIra;
+CSceneTest g_sceneTest;
+CSceneHand g_sceneHand;
+CSceneDragon g_sceneDragon;
+CSceneLPSHead g_sceneLPSHead;
+CSceneManjaladon g_sceneManjaladon;
+CSceneWarriorHead g_sceneWarriorHead;
+CScene * g_pSceneCur = nullptr;
+
+CBackground g_bkgndBlack;
+CBackground g_bkgndCharcoal;
+CBackground g_bkgndForest;
+CBackground g_bkgndNight;
+CBackground g_bkgndTunnel;
+CBackground * g_pBkgndCur = nullptr;
+
+CMesh g_meshFullscreen;
+
+ID3D11ShaderResourceView * g_pSrvCurvatureLUT = nullptr;
+static const float g_curvatureRadiusMinLUT = 0.1f; // cm
+static const float g_curvatureRadiusMaxLUT = 10.0f; // cm
+
+ID3D11ShaderResourceView * g_pSrvShadowLUT = nullptr;
+static const float g_shadowWidthMinLUT = 0.8f; // cm
+static const float g_shadowWidthMaxLUT = 10.0f; // cm
+
+ID3D11DepthStencilState * g_pDssDepthTest = nullptr;
+ID3D11DepthStencilState * g_pDssNoDepthTest = nullptr;
+ID3D11DepthStencilState * g_pDssNoDepthWrite = nullptr;
+ID3D11RasterizerState * g_pRsSolid = nullptr;
+ID3D11RasterizerState * g_pRsWireframe = nullptr;
+ID3D11RasterizerState * g_pRsSolidDoubleSided = nullptr;
+ID3D11BlendState * g_pBsAlphaBlend = nullptr;
+
+CShadowMap g_shadowmap;
+CVarShadowMap g_vsm;
+
+ID3D11RenderTargetView * g_pRtvNonSrgb = nullptr;
+
+float g_radYawDirectionalLight = 0.70f;
+float g_radPitchDirectionalLight = 0.40f;
+XMVECTOR g_vecDirectionalLight;
+XMVECTOR g_rgbDirectionalLight;
+float g_directionalLightBrightness = 1.0f;
+
+float g_vsmBlurRadius = 0.15f; // One-sigma radius, in cm
+float g_vsmMinVariance = 1e-4f;
+float g_shadowSharpening = 10.0f;
+
+float g_sssBlurRadius = 0.27f; // One-sigma radius of widest Gaussian, in cm
+
+float g_tessErrPx = 0.5f; // Target tessellation error, in pixels
+
+float g_deepScatterIntensity = 0.5f; // Multiplier on whole deep scattering result
+float g_deepScatterRadius = 0.6f; // One-sigma radius of deep scatter Gaussian, in cm
+float g_deepScatterNormalOffset = -0.0007f; // Normal offset for shadow lookup to calculate thickness
+float g_deepScatterShadowRadius = 1.1f; // Poisson disk radius, in cm
+
+float g_debugSlider0 = 0.0f;
+float g_debugSlider1 = 0.0f;
+float g_debugSlider2 = 0.0f;
+float g_debugSlider3 = 0.0f;
+
+// Copy a texture to a rectangle of a render target
+// Rectangle is specified as a XMFLOAT4 of (left, top, width, height) in pixels
+void CopyTexture(
+ ID3D11DeviceContext * pCtx,
+ ID3D11ShaderResourceView * pSrvSrc,
+ ID3D11RenderTargetView * pRtvDest,
+ ID3D11DepthStencilView * pDsvDest,
+ const XMFLOAT4 & rectDest,
+ const XMFLOAT4X4 * pMatTransformColor = nullptr);
+
+// Macros for checking FaceWorks return codes
+#if defined(_DEBUG)
+# define NV(x) { GFSDK_FaceWorks_Result res = (x); if (res != GFSDK_FaceWorks_OK) { DXUTTrace(__FILE__, __LINE__, E_FAIL, L#x, true); } }
+# define NV_RETURN(x) { GFSDK_FaceWorks_Result res = (x); if (res != GFSDK_FaceWorks_OK) { return DXUTTrace(__FILE__, __LINE__, E_FAIL, L#x, true); } }
+#else
+# define NV(x) x
+# define NV_RETURN(x) { GFSDK_FaceWorks_Result res = (x); if (res != GFSDK_FaceWorks_OK) { return E_FAIL; } }
+#endif
+
+
+
+HRESULT InitScene()
+{
+ HRESULT hr;
+ wchar_t strPath[MAX_PATH];
+ ID3D11Device * pDevice = DXUTGetD3D11Device();
+
+ // Init FaceWorks
+ NV_RETURN(GFSDK_FaceWorks_Init());
+
+ V_RETURN(CreateFullscreenMesh(pDevice, &g_meshFullscreen));
+
+ // Load scenes
+ V_RETURN(g_sceneDigitalIra.Init());
+ V_RETURN(g_sceneTest.Init());
+ V_RETURN(g_sceneHand.Init());
+ V_RETURN(g_sceneDragon.Init());
+ V_RETURN(g_sceneLPSHead.Init());
+ V_RETURN(g_sceneManjaladon.Init());
+ V_RETURN(g_sceneWarriorHead.Init());
+ g_pSceneCur = &g_sceneDigitalIra;
+
+ // Load backgrounds
+ V_RETURN(g_bkgndBlack.Init(L"HDREnvironments\\black_cube.dds", L"HDREnvironments\\black_cube.dds", L"HDREnvironments\\black_cube.dds"));
+ V_RETURN(g_bkgndCharcoal.Init(L"HDREnvironments\\charcoal_cube.dds", L"HDREnvironments\\charcoal_cube.dds", L"HDREnvironments\\charcoal_cube.dds"));
+ V_RETURN(g_bkgndForest.Init(L"HDREnvironments\\forest_env_cubemap.dds", L"HDREnvironments\\forest_diffuse_cubemap.dds", L"HDREnvironments\\forest_spec_cubemap.dds", 0.25f));
+ V_RETURN(g_bkgndNight.Init(L"HDREnvironments\\night_env_cubemap.dds", L"HDREnvironments\\night_diffuse_cubemap.dds", L"HDREnvironments\\night_spec_cubemap.dds"));
+ V_RETURN(g_bkgndTunnel.Init(L"HDREnvironments\\tunnel_env_cubemap.dds", L"HDREnvironments\\tunnel_diffuse_cubemap.dds", L"HDREnvironments\\tunnel_spec_cubemap.dds", 0.5f));
+ g_pBkgndCur = &g_bkgndCharcoal;
+
+ // Load textures
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"curvatureLUT.bmp"));
+ V_RETURN(LoadTexture(strPath, pDevice, &g_pSrvCurvatureLUT, LT_Linear));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"shadowLUT.bmp"));
+ V_RETURN(LoadTexture(strPath, pDevice, &g_pSrvShadowLUT, LT_None));
+
+ // Load shaders
+ V_RETURN(g_shdmgr.Init(pDevice));
+
+ // Create depth-stencil states
+
+ D3D11_DEPTH_STENCIL_DESC dssDepthTestDesc =
+ {
+ true, // DepthEnable
+ D3D11_DEPTH_WRITE_MASK_ALL,
+ D3D11_COMPARISON_LESS_EQUAL,
+ };
+ V_RETURN(pDevice->CreateDepthStencilState(&dssDepthTestDesc, &g_pDssDepthTest));
+
+ D3D11_DEPTH_STENCIL_DESC dssNoDepthTestDesc =
+ {
+ false, // DepthEnable
+ };
+ V_RETURN(pDevice->CreateDepthStencilState(&dssNoDepthTestDesc, &g_pDssNoDepthTest));
+
+ D3D11_DEPTH_STENCIL_DESC dssNoDepthWriteDesc =
+ {
+ true, // DepthEnable
+ D3D11_DEPTH_WRITE_MASK_ZERO,
+ D3D11_COMPARISON_LESS_EQUAL,
+ };
+ V_RETURN(pDevice->CreateDepthStencilState(&dssNoDepthWriteDesc, &g_pDssNoDepthWrite));
+
+ // Create rasterizer states
+
+ D3D11_RASTERIZER_DESC rssSolidDesc =
+ {
+ D3D11_FILL_SOLID,
+ D3D11_CULL_BACK,
+ true, // FrontCounterClockwise
+ 0, 0, 0, // depth bias
+ true, // DepthClipEnable
+ false, // ScissorEnable
+ true, // MultisampleEnable
+ };
+ V_RETURN(pDevice->CreateRasterizerState(&rssSolidDesc, &g_pRsSolid));
+
+ D3D11_RASTERIZER_DESC rssWireframeDesc =
+ {
+ D3D11_FILL_WIREFRAME,
+ D3D11_CULL_BACK,
+ true, // FrontCounterClockwise
+ 0, 0, 0, // depth bias
+ true, // DepthClipEnable
+ false, // ScissorEnable
+ true, // MultisampleEnable
+ };
+ V_RETURN(pDevice->CreateRasterizerState(&rssWireframeDesc, &g_pRsWireframe));
+
+ D3D11_RASTERIZER_DESC rssSolidDoubleSidedDesc =
+ {
+ D3D11_FILL_SOLID,
+ D3D11_CULL_NONE,
+ true, // FrontCounterClockwise
+ 0, 0, 0, // depth bias
+ true, // DepthClipEnable
+ false, // ScissorEnable
+ true, // MultisampleEnable
+ };
+ V_RETURN(pDevice->CreateRasterizerState(&rssSolidDoubleSidedDesc, &g_pRsSolidDoubleSided));
+
+ // Initialize the blend state for alpha-blending
+
+ D3D11_BLEND_DESC bsDesc =
+ {
+ false, false,
+ {
+ true,
+ D3D11_BLEND_SRC_ALPHA,
+ D3D11_BLEND_INV_SRC_ALPHA,
+ D3D11_BLEND_OP_ADD,
+ D3D11_BLEND_SRC_ALPHA,
+ D3D11_BLEND_INV_SRC_ALPHA,
+ D3D11_BLEND_OP_ADD,
+ D3D11_COLOR_WRITE_ENABLE_ALL,
+ },
+ };
+
+ V_RETURN(pDevice->CreateBlendState(&bsDesc, &g_pBsAlphaBlend));
+
+ // Create shadow map
+ g_shadowmap.Init(1024, pDevice);
+ g_vsm.Init(1024, pDevice);
+
+ // Set up GPU profiler
+ V_RETURN(g_gpuProfiler.Init(pDevice));
+
+ // Set up directional light
+ g_rgbDirectionalLight = XMVectorSet(0.984f, 1.0f, 0.912f, 0.0f); // Note: linear RGB space
+
+ return S_OK;
+}
+
+void CALLBACK OnD3D11DestroyDevice(void * /*pUserContext*/)
+{
+ g_DialogResourceManager.OnD3D11DestroyDevice();
+ DXUTGetGlobalResourceCache().OnDestroyDevice();
+ SAFE_DELETE(g_pTxtHelper);
+
+ g_sceneDigitalIra.Release();
+ g_sceneTest.Release();
+ g_sceneHand.Release();
+ g_sceneDragon.Release();
+ g_sceneLPSHead.Release();
+ g_sceneManjaladon.Release();
+ g_sceneWarriorHead.Release();
+
+ g_bkgndBlack.Release();
+ g_bkgndCharcoal.Release();
+ g_bkgndForest.Release();
+ g_bkgndNight.Release();
+ g_bkgndTunnel.Release();
+
+ g_meshFullscreen.Release();
+
+ SAFE_RELEASE(g_pSrvCurvatureLUT);
+ SAFE_RELEASE(g_pSrvShadowLUT);
+
+ g_shdmgr.Release();
+
+ SAFE_RELEASE(g_pDssDepthTest);
+ SAFE_RELEASE(g_pDssNoDepthTest);
+ SAFE_RELEASE(g_pDssNoDepthWrite);
+ SAFE_RELEASE(g_pRsSolid);
+ SAFE_RELEASE(g_pRsWireframe);
+ SAFE_RELEASE(g_pRsSolidDoubleSided);
+ SAFE_RELEASE(g_pBsAlphaBlend);
+
+ g_shadowmap.Release();
+ g_vsm.Release();
+
+ g_gpuProfiler.Release();
+
+#if defined(_DEBUG)
+ HRESULT hr;
+
+ // Report any remaining live objects
+ ID3D11Debug * pD3DDebug = nullptr;
+ V(DXUTGetD3D11Device()->QueryInterface(IID_ID3D11Debug, reinterpret_cast<void **>(&pD3DDebug)));
+
+ ID3D11InfoQueue * pInfoQueue = nullptr;
+ V(DXUTGetD3D11Device()->QueryInterface(IID_ID3D11InfoQueue, reinterpret_cast<void **>(&pInfoQueue)));
+
+ // Destroy all pending objects
+ DXUTGetD3D11DeviceContext()->ClearState();
+ DXUTGetD3D11DeviceContext()->Flush();
+
+ // Turn off breaking on warnings (DXUT automatically checks live objects on exit)
+ pInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING, false);
+
+ SAFE_RELEASE(pInfoQueue);
+ SAFE_RELEASE(pD3DDebug);
+#endif
+}
+
+void CALLBACK OnFrameMove(double /*fTime*/, float fElapsedTime, void * /*pUserContext*/)
+{
+ g_pSceneCur->Camera()->FrameMove(fElapsedTime);
+}
+
+void CALLBACK OnD3D11FrameRender(
+ ID3D11Device * /*pd3dDevice*/,
+ ID3D11DeviceContext * pd3dContext,
+ double /*fTime*/, float fElapsedTime,
+ void * /*pUserContext*/)
+{
+ HRESULT hr;
+
+ pd3dContext->ClearState();
+
+ g_gpuProfiler.BeginFrame(pd3dContext);
+
+ // Set up directional light and shadow map
+ g_vecDirectionalLight = XMVectorSet(
+ sinf(g_radYawDirectionalLight) * cosf(g_radPitchDirectionalLight),
+ sinf(g_radPitchDirectionalLight),
+ cosf(g_radYawDirectionalLight) * cosf(g_radPitchDirectionalLight),
+ 0.0f);
+
+
+ XMStoreFloat3(&g_shadowmap.m_vecLight, g_vecDirectionalLight);
+
+ g_pSceneCur->GetBounds(&g_shadowmap.m_posMinScene, &g_shadowmap.m_posMaxScene);
+ g_shadowmap.UpdateMatrix();
+
+ // Calculate UV space blur radius using shadow map's diameter, to attempt to maintain a
+ // constant blur radius in world space.
+ g_vsm.m_blurRadius = g_vsmBlurRadius / min(g_shadowmap.m_vecDiam.x, g_shadowmap.m_vecDiam.y);
+
+ // Get the list of stuff to draw for the current scene
+ std::vector<MeshToDraw> meshesToDraw;
+ g_pSceneCur->GetMeshesToDraw(&meshesToDraw);
+ int cMeshToDraw = int(meshesToDraw.size());
+
+ // Set up whole-frame textures, constant buffers, etc.
+
+ bool bDebug = (GetAsyncKeyState(' ') != 0);
+ float debug = bDebug ? 1.0f : 0.0f;
+
+ CbufDebug cbDebug =
+ {
+ debug,
+ g_debugSlider0,
+ g_debugSlider1,
+ g_debugSlider2,
+ g_debugSlider3,
+ };
+
+ // Get the view and proj matrices from the camera
+ XMMATRIX matView = g_pSceneCur->Camera()->GetViewMatrix();
+ XMMATRIX matProj = g_pSceneCur->Camera()->GetProjMatrix();
+ XMFLOAT4X4 matWorldToClip; XMStoreFloat4x4(&matWorldToClip, matView * matProj);
+ XMFLOAT4 posCamera; XMStoreFloat4(&posCamera, g_pSceneCur->Camera()->GetEyePt());
+
+ XMMATRIX matViewAxes(
+ matView.r[0],
+ matView.r[1],
+ matView.r[2],
+ XMVectorSelect(matView.r[3], g_XMZero, g_XMSelect1110));
+ XMMATRIX matViewAxesInverse = XMMatrixInverse(nullptr, matViewAxes);
+ XMMATRIX matProjInverse = XMMatrixInverse(nullptr, matProj);
+ XMFLOAT4X4 matClipToWorldAxes; XMStoreFloat4x4(&matClipToWorldAxes, matProjInverse * matViewAxesInverse);
+
+ // Calculate tessellation scale using screen-space error. The 0.41 is a curve fitting constant.
+ // Error goes inversely as the square of the tess factor (for edges that are small wrt curvature),
+ // so tess factor goes inversely as the square root of the target error.
+ float tessScale = 0.41f / sqrtf(g_tessErrPx * 2.0f * tanf(0.5f * g_FOV) / float(DXUTGetWindowHeight()));
+
+ XMFLOAT4 vecDirectionalLight; XMStoreFloat4(&vecDirectionalLight, g_vecDirectionalLight);
+ XMFLOAT4 rgbDirectionalLight; XMStoreFloat4(&rgbDirectionalLight, g_directionalLightBrightness * g_rgbDirectionalLight);
+
+ CbufFrame cbFrame =
+ {
+ matWorldToClip,
+ posCamera,
+ vecDirectionalLight,
+ rgbDirectionalLight,
+ g_shadowmap.m_matWorldToUvzw,
+ {
+ XMFLOAT4(g_shadowmap.m_matWorldToUvzNormal.m[0]),
+ XMFLOAT4(g_shadowmap.m_matWorldToUvzNormal.m[1]),
+ XMFLOAT4(g_shadowmap.m_matWorldToUvzNormal.m[2]),
+ },
+ g_vsmMinVariance,
+ g_shadowSharpening,
+ tessScale,
+ g_deepScatterIntensity,
+ g_deepScatterNormalOffset,
+ g_pBkgndCur->m_exposure,
+ };
+
+ g_shdmgr.InitFrame(
+ pd3dContext,
+ &cbDebug,
+ &cbFrame,
+ g_pBkgndCur->m_pSrvCubeDiff,
+ g_pBkgndCur->m_pSrvCubeSpec,
+ g_pSrvCurvatureLUT,
+ g_pSrvShadowLUT);
+
+ // Clear the shadow map
+ pd3dContext->ClearDepthStencilView(g_shadowmap.m_pDsv, D3D11_CLEAR_DEPTH, 1.0f, 0);
+
+ g_shadowmap.BindRenderTarget(pd3dContext);
+ pd3dContext->OMSetDepthStencilState(g_pDssDepthTest, 0);
+ pd3dContext->RSSetState(g_pRsSolid);
+
+ // Draw shadow map
+
+ g_shdmgr.BindShadow(pd3dContext, g_shadowmap.m_matWorldToClip);
+ for (int i = 0; i < cMeshToDraw; ++i)
+ {
+ meshesToDraw[i].m_pMesh->Draw(pd3dContext);
+ }
+
+ g_vsm.UpdateFromShadowMap(g_shadowmap, pd3dContext);
+ g_vsm.GaussianBlur(pd3dContext);
+
+ g_gpuProfiler.Timestamp(pd3dContext, GTS_ShadowMap);
+
+ // Bind the non-SRGB render target view, for rendering with tone mapping
+ // (which outputs in SRGB gamma space natively)
+ V(DXUTSetupD3D11Views(pd3dContext));
+ pd3dContext->OMSetRenderTargets(1, &g_pRtvNonSrgb, DXUTGetD3D11DepthStencilView());
+ pd3dContext->RSSetState(g_bWireframe ? g_pRsWireframe : g_pRsSolid);
+
+ // Clear the screen
+ float rgbaZero[4] = {};
+ pd3dContext->ClearRenderTargetView(DXUTGetD3D11RenderTargetView(), rgbaZero);
+ pd3dContext->ClearDepthStencilView(DXUTGetD3D11DepthStencilView(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
+
+ g_shdmgr.BindShadowTextures(
+ pd3dContext,
+ g_shadowmap.m_pSrv,
+ g_vsm.m_pSrv);
+
+ SHDFEATURES features = 0;
+ if (g_bTessellation)
+ features |= SHDFEAT_Tessellation;
+
+ switch (g_renderMethod)
+ {
+ case RM_None:
+ {
+ // Note: two loops for skin and eye materials so we can have GPU timestamps around
+ // each shader individually. Gack.
+
+ // Draw skin shaders
+ for (int i = 0; i < cMeshToDraw; ++i)
+ {
+ if (meshesToDraw[i].m_pMtl->m_shader == SHADER_Skin)
+ {
+ g_shdmgr.BindMaterial(pd3dContext, features, meshesToDraw[i].m_pMtl);
+ meshesToDraw[i].m_pMesh->Draw(pd3dContext);
+ }
+ }
+ g_gpuProfiler.Timestamp(pd3dContext, GTS_Skin);
+
+ // Draw eye shaders
+ for (int i = 0; i < cMeshToDraw; ++i)
+ {
+ if (meshesToDraw[i].m_pMtl->m_shader == SHADER_Eye)
+ {
+ g_shdmgr.BindMaterial(pd3dContext, features, meshesToDraw[i].m_pMtl);
+ meshesToDraw[i].m_pMesh->Draw(pd3dContext);
+ }
+ }
+ g_gpuProfiler.Timestamp(pd3dContext, GTS_Eyes);
+ }
+ break;
+
+ case RM_SSS:
+ case RM_SSSAndDeep:
+ {
+ GFSDK_FaceWorks_SSSConfig sssConfigSkin = {}, sssConfigEye;
+ sssConfigSkin.m_diffusionRadius = max(g_sssBlurRadius, 0.01f);
+ sssConfigSkin.m_diffusionRadiusLUT = 0.27f;
+
+ sssConfigSkin.m_curvatureRadiusMinLUT = g_curvatureRadiusMinLUT;
+ sssConfigSkin.m_curvatureRadiusMaxLUT = g_curvatureRadiusMaxLUT;
+ sssConfigSkin.m_shadowWidthMinLUT = g_shadowWidthMinLUT;
+ sssConfigSkin.m_shadowWidthMaxLUT = g_shadowWidthMaxLUT;
+
+ // Filter width is ~6 times the Gaussian sigma
+ sssConfigSkin.m_shadowFilterWidth = max(6.0f * g_vsmBlurRadius, 0.01f);
+
+ sssConfigEye = sssConfigSkin;
+
+ GFSDK_FaceWorks_DeepScatterConfig deepScatterConfigSkin = {}, deepScatterConfigEye;
+ deepScatterConfigSkin.m_radius = max(g_deepScatterRadius, 0.01f);
+ deepScatterConfigSkin.m_shadowProjType = GFSDK_FaceWorks_ParallelProjection;
+ memcpy(&deepScatterConfigSkin.m_shadowProjMatrix, &g_shadowmap.m_matProj, 16 * sizeof(float));
+ deepScatterConfigSkin.m_shadowFilterRadius = g_deepScatterShadowRadius / min(g_shadowmap.m_vecDiam.x, g_shadowmap.m_vecDiam.y);
+
+ deepScatterConfigEye = deepScatterConfigSkin;
+
+ features |= SHDFEAT_SSS;
+ if (g_renderMethod == RM_SSSAndDeep)
+ features |= SHDFEAT_DeepScatter;
+
+ GFSDK_FaceWorks_ErrorBlob faceworksErrors = {};
+
+ // Note: two loops for skin and eye materials so we can have GPU timestamps around
+ // each shader individually. Gack.
+
+ // Draw skin shaders
+ for (int i = 0; i < cMeshToDraw; ++i)
+ {
+ if (meshesToDraw[i].m_pMtl->m_shader == SHADER_Skin)
+ {
+ sssConfigSkin.m_normalMapSize = meshesToDraw[i].m_normalMapSize;
+ sssConfigSkin.m_averageUVScale = meshesToDraw[i].m_averageUVScale;
+ NV(GFSDK_FaceWorks_WriteCBDataForSSS(
+ &sssConfigSkin, reinterpret_cast<GFSDK_FaceWorks_CBData *>(&meshesToDraw[i].m_pMtl->m_constants[4]), &faceworksErrors));
+ NV(GFSDK_FaceWorks_WriteCBDataForDeepScatter(
+ &deepScatterConfigSkin, reinterpret_cast<GFSDK_FaceWorks_CBData *>(&meshesToDraw[i].m_pMtl->m_constants[4]), &faceworksErrors));
+
+ g_shdmgr.BindMaterial(pd3dContext, features, meshesToDraw[i].m_pMtl);
+ meshesToDraw[i].m_pMesh->Draw(pd3dContext);
+ }
+ }
+ g_gpuProfiler.Timestamp(pd3dContext, GTS_Skin);
+
+ // Draw eye shaders
+ for (int i = 0; i < cMeshToDraw; ++i)
+ {
+ if (meshesToDraw[i].m_pMtl->m_shader == SHADER_Eye)
+ {
+ sssConfigEye.m_normalMapSize = meshesToDraw[i].m_normalMapSize;
+ sssConfigEye.m_averageUVScale = meshesToDraw[i].m_averageUVScale;
+ NV(GFSDK_FaceWorks_WriteCBDataForSSS(
+ &sssConfigEye, reinterpret_cast<GFSDK_FaceWorks_CBData *>(&meshesToDraw[i].m_pMtl->m_constants[12]), &faceworksErrors));
+ NV(GFSDK_FaceWorks_WriteCBDataForDeepScatter(
+ &deepScatterConfigEye, reinterpret_cast<GFSDK_FaceWorks_CBData *>(&meshesToDraw[i].m_pMtl->m_constants[12]), &faceworksErrors));
+
+ g_shdmgr.BindMaterial(pd3dContext, features, meshesToDraw[i].m_pMtl);
+ meshesToDraw[i].m_pMesh->Draw(pd3dContext);
+ }
+ }
+ g_gpuProfiler.Timestamp(pd3dContext, GTS_Eyes);
+
+ if (faceworksErrors.m_msg)
+ {
+#if defined(_DEBUG)
+ wchar_t msg[512];
+ _snwprintf_s(msg, dim(msg),
+ L"FaceWorks rendering error:\n%hs", faceworksErrors.m_msg);
+ DXUTTrace(__FILE__, __LINE__, E_FAIL, msg, true);
+#endif
+ GFSDK_FaceWorks_FreeErrorBlob(&faceworksErrors);
+ }
+ }
+ break;
+
+ case RM_ViewCurvature:
+ {
+ // Calculate scale-bias for mapping curvature to LUT coordinate,
+ // given the min and max curvature encoded in the LUT.
+
+ float curvatureScale = 1.0f / (1.0f / g_curvatureRadiusMinLUT - 1.0f / g_curvatureRadiusMaxLUT);
+ float curvatureBias = 1.0f / (1.0f - g_curvatureRadiusMaxLUT / g_curvatureRadiusMinLUT);
+
+ g_shdmgr.BindCurvature(pd3dContext, curvatureScale, curvatureBias);
+
+ for (int i = 0; i < cMeshToDraw; ++i)
+ {
+ meshesToDraw[i].m_pMesh->Draw(pd3dContext);
+ }
+ }
+ break;
+
+ case RM_ViewThickness:
+ {
+ GFSDK_FaceWorks_DeepScatterConfig deepScatterConfigSkin = {};
+ deepScatterConfigSkin.m_radius = max(g_deepScatterRadius, 0.01f);
+ deepScatterConfigSkin.m_shadowProjType = GFSDK_FaceWorks_ParallelProjection;
+ memcpy(&deepScatterConfigSkin.m_shadowProjMatrix, &g_shadowmap.m_matProj, 16 * sizeof(float));
+ deepScatterConfigSkin.m_shadowFilterRadius = g_deepScatterShadowRadius / min(g_shadowmap.m_vecDiam.x, g_shadowmap.m_vecDiam.y);
+
+ GFSDK_FaceWorks_CBData faceworksCBData = {};
+ GFSDK_FaceWorks_ErrorBlob faceworksErrors = {};
+
+ NV(GFSDK_FaceWorks_WriteCBDataForDeepScatter(
+ &deepScatterConfigSkin, &faceworksCBData, &faceworksErrors));
+
+ if (faceworksErrors.m_msg)
+ {
+#if defined(_DEBUG)
+ wchar_t msg[512];
+ _snwprintf_s(msg, dim(msg),
+ L"FaceWorks rendering error:\n%hs", faceworksErrors.m_msg);
+ DXUTTrace(__FILE__, __LINE__, E_FAIL, msg, true);
+#endif
+ GFSDK_FaceWorks_FreeErrorBlob(&faceworksErrors);
+ }
+
+ g_shdmgr.BindThickness(pd3dContext, &faceworksCBData);
+
+ for (int i = 0; i < cMeshToDraw; ++i)
+ {
+ meshesToDraw[i].m_pMesh->Draw(pd3dContext);
+ }
+ }
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+
+ g_shdmgr.UnbindTess(pd3dContext);
+
+ // Draw the skybox
+ pd3dContext->RSSetState(g_pRsSolid);
+ g_shdmgr.BindSkybox(pd3dContext, g_pBkgndCur->m_pSrvCubeEnv, matClipToWorldAxes);
+ g_meshFullscreen.Draw(pd3dContext);
+
+ // Draw hair shaders, with alpha blending
+ pd3dContext->RSSetState(g_pRsSolidDoubleSided);
+ pd3dContext->OMSetDepthStencilState(g_pDssNoDepthWrite, 0);
+ pd3dContext->OMSetBlendState(g_pBsAlphaBlend, nullptr, ~0UL);
+ for (int i = 0; i < cMeshToDraw; ++i)
+ {
+ if (meshesToDraw[i].m_pMtl->m_shader == SHADER_Hair)
+ {
+ g_shdmgr.BindMaterial(pd3dContext, 0, meshesToDraw[i].m_pMtl);
+ meshesToDraw[i].m_pMesh->Draw(pd3dContext);
+ }
+ }
+ pd3dContext->RSSetState(g_pRsSolid);
+ pd3dContext->OMSetDepthStencilState(g_pDssDepthTest, 0);
+ pd3dContext->OMSetBlendState(nullptr, nullptr, ~0UL);
+
+ // Now switch to the SRGB back buffer view, for compositing UI
+ V(DXUTSetupD3D11Views(pd3dContext));
+
+ // Show the shadow map if desired
+
+ if (g_viewbuf == VIEWBUF_ShadowMap)
+ {
+ // Copy red channel to RGB channels
+ XMFLOAT4X4 matTransformColor(
+ 1, 1, 1, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 1);
+
+ CopyTexture(
+ pd3dContext, g_shadowmap.m_pSrv,
+ DXUTGetD3D11RenderTargetView(), nullptr,
+ s_rectViewBuffer,
+ &matTransformColor);
+ V(DXUTSetupD3D11Views(pd3dContext));
+ }
+
+ // Render GUI and text
+
+ if (g_ShowGUI)
+ {
+ UpdateSliders();
+ g_HUD.OnRender(fElapsedTime);
+ }
+
+ g_gpuProfiler.WaitForDataAndUpdate(pd3dContext);
+
+ if (g_ShowText)
+ {
+ RenderText();
+ }
+
+ g_gpuProfiler.EndFrame(pd3dContext);
+}
+
+
+
+bool CALLBACK IsD3D11DeviceAcceptable(
+ const CD3D11EnumAdapterInfo * /*AdapterInfo*/,
+ UINT /*Output*/,
+ const CD3D11EnumDeviceInfo * /*DeviceInfo*/,
+ DXGI_FORMAT /*BackBufferFormat*/,
+ bool /*bWindowed*/,
+ void * /*pUserContext*/)
+{
+ // Any D3D11 device is ok
+ return true;
+}
+
+bool CALLBACK ModifyDeviceSettings(DXUTDeviceSettings * pDeviceSettings, void * /*pUserContext*/)
+{
+ // Disable vsync
+ pDeviceSettings->d3d11.SyncInterval = 0;
+
+ // For the first device created if it is a REF device, display a warning dialog box
+ static bool s_bFirstTime = true;
+ if (s_bFirstTime)
+ {
+ s_bFirstTime = false;
+
+ if (pDeviceSettings->d3d11.DriverType == D3D_DRIVER_TYPE_REFERENCE)
+ {
+ DXUTDisplaySwitchingToREFWarning();
+ }
+
+ // Request 4x MSAA
+ pDeviceSettings->d3d11.sd.SampleDesc.Count = 4;
+ }
+
+ return true;
+}
+
+HRESULT CALLBACK OnD3D11CreateDevice(
+ ID3D11Device * pd3dDevice,
+ const DXGI_SURFACE_DESC * /*pBackBufferSurfaceDesc*/,
+ void * /*pUserContext*/)
+{
+ HRESULT hr;
+
+#if defined(_DEBUG)
+ // Set up D3D11 debug layer settings
+ ID3D11InfoQueue * pInfoQueue = nullptr;
+ V_RETURN(pd3dDevice->QueryInterface(IID_ID3D11InfoQueue, reinterpret_cast<void **>(&pInfoQueue)));
+
+ // Break in the debugger when an error or warning is issued
+ pInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true);
+ pInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true);
+ pInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING, true);
+
+ // Disable warning about setting private data (i.e. debug names of resources)
+ D3D11_MESSAGE_ID aMsgToFilter[] =
+ {
+ D3D11_MESSAGE_ID_SETPRIVATEDATA_CHANGINGPARAMS,
+ };
+ D3D11_INFO_QUEUE_FILTER filter = {};
+ filter.DenyList.NumIDs = dim(aMsgToFilter);
+ filter.DenyList.pIDList = aMsgToFilter;
+ pInfoQueue->AddStorageFilterEntries(&filter);
+
+ SAFE_RELEASE(pInfoQueue);
+#endif
+
+ ID3D11DeviceContext * pd3dContext = DXUTGetD3D11DeviceContext();
+ V_RETURN(g_DialogResourceManager.OnD3D11CreateDevice(pd3dDevice, pd3dContext));
+ g_pTxtHelper = new CDXUTTextHelper(pd3dDevice, pd3dContext, &g_DialogResourceManager, 15);
+
+ V_RETURN(InitScene());
+
+ return S_OK;
+}
+
+HRESULT CALLBACK OnD3D11ResizedSwapChain(
+ ID3D11Device * pd3dDevice,
+ IDXGISwapChain * pSwapChain,
+ const DXGI_SURFACE_DESC * pBackBufferSurfaceDesc,
+ void * /*pUserContext*/)
+{
+ HRESULT hr;
+
+ // Inform UI elements of the new size
+
+ V_RETURN(g_DialogResourceManager.OnD3D11ResizedSwapChain(pd3dDevice, pBackBufferSurfaceDesc));
+
+ UINT MainHudWidth = 200;
+ g_HUD.SetLocation(pBackBufferSurfaceDesc->Width - MainHudWidth, 0);
+ g_HUD.SetSize(MainHudWidth, pBackBufferSurfaceDesc->Height);
+
+ // Regenerate camera projection matrices with the new aspect ratio
+
+ static const float NEAR_PLANE = 0.1f;
+ static const float FAR_PLANE = 1e5f;
+
+ g_sceneDigitalIra.Camera()->SetProjParams(
+ g_FOV,
+ float(pBackBufferSurfaceDesc->Width) / float(pBackBufferSurfaceDesc->Height),
+ NEAR_PLANE,
+ FAR_PLANE);
+
+ g_sceneTest.Camera()->SetProjParams(
+ g_FOV,
+ float(pBackBufferSurfaceDesc->Width) / float(pBackBufferSurfaceDesc->Height),
+ NEAR_PLANE,
+ FAR_PLANE);
+
+ g_sceneHand.Camera()->SetProjParams(
+ g_FOV,
+ float(pBackBufferSurfaceDesc->Width) / float(pBackBufferSurfaceDesc->Height),
+ NEAR_PLANE,
+ FAR_PLANE);
+
+ g_sceneDragon.Camera()->SetProjParams(
+ g_FOV,
+ float(pBackBufferSurfaceDesc->Width) / float(pBackBufferSurfaceDesc->Height),
+ NEAR_PLANE,
+ FAR_PLANE);
+
+ g_sceneLPSHead.Camera()->SetProjParams(
+ g_FOV,
+ float(pBackBufferSurfaceDesc->Width) / float(pBackBufferSurfaceDesc->Height),
+ NEAR_PLANE,
+ FAR_PLANE);
+
+ g_sceneManjaladon.Camera()->SetProjParams(
+ g_FOV,
+ float(pBackBufferSurfaceDesc->Width) / float(pBackBufferSurfaceDesc->Height),
+ NEAR_PLANE,
+ FAR_PLANE);
+
+ g_sceneWarriorHead.Camera()->SetProjParams(
+ g_FOV,
+ float(pBackBufferSurfaceDesc->Width) / float(pBackBufferSurfaceDesc->Height),
+ NEAR_PLANE,
+ FAR_PLANE);
+
+ // Regenerate the non-SRGB render target view
+
+ if (g_pRtvNonSrgb)
+ {
+ g_pRtvNonSrgb->Release();
+ g_pRtvNonSrgb = nullptr;
+ }
+
+ ID3D11Texture2D * pBackBuffer;
+ V_RETURN(pSwapChain->GetBuffer(0, IID_ID3D11Texture2D, reinterpret_cast<void **>(&pBackBuffer)));
+
+ D3D11_RENDER_TARGET_VIEW_DESC rtvDesc =
+ {
+ DXGI_FORMAT_R8G8B8A8_UNORM,
+ D3D11_RTV_DIMENSION_TEXTURE2DMS,
+ };
+ V_RETURN(pd3dDevice->CreateRenderTargetView(pBackBuffer, &rtvDesc, &g_pRtvNonSrgb));
+
+ pBackBuffer->Release();
+
+ return S_OK;
+}
+
+void CALLBACK OnD3D11ReleasingSwapChain(void * /*pUserContext*/)
+{
+ g_DialogResourceManager.OnD3D11ReleasingSwapChain();
+
+ if (g_pRtvNonSrgb)
+ {
+ g_pRtvNonSrgb->Release();
+ g_pRtvNonSrgb = nullptr;
+ }
+}
+
+
+
+// UI control IDs
+enum
+{
+ IDC_ABOUT = 1,
+
+ IDC_SCENE,
+ IDC_BKGND,
+ IDC_SSS_METHOD,
+
+ IDC_CAMERA_WIDE,
+ IDC_CAMERA_CLOSE,
+ IDC_CAMERA_EYE,
+ IDC_VIEW_BUFFER,
+
+ IDC_SLIDER_BASE,
+};
+
+enum
+{
+ GROUP_LIGHT,
+ GROUP_SUBSURFACE,
+ GROUP_SHADOW,
+ GROUP_MTL,
+ GROUP_EYE,
+ GROUP_DEEPSCATTER,
+ GROUP_DEBUG,
+};
+
+struct Slider
+{
+ int m_group;
+ const wchar_t * m_strCaption;
+ float m_min, m_max;
+ float * m_pValue;
+ int m_steps;
+};
+
+extern float g_normalStrength;
+extern float g_glossSkin;
+extern float g_glossEye;
+extern float g_irisRadiusSource;
+extern float g_irisRadiusDest;
+extern float g_irisEdgeHardness;
+extern float g_irisDilation;
+extern float g_specReflectanceHair;
+extern float g_glossHair;
+
+static const Slider g_aSlider[] =
+{
+ { GROUP_LIGHT, L"Light yaw: %0.2f", -XM_PI, XM_PI, &g_radYawDirectionalLight },
+ { GROUP_LIGHT, L"Light pitch: %0.2f", -XM_PIDIV2, XM_PIDIV2, &g_radPitchDirectionalLight },
+ { GROUP_LIGHT, L"Light brightness: %0.1f", 0.0f, 5.0f, &g_directionalLightBrightness },
+
+ { GROUP_SUBSURFACE, L"SSS radius (cm): %0.2f", 0.0f, 1.0f, &g_sssBlurRadius },
+
+ { GROUP_MTL, L"Normal strength: %0.2f", 0.0f, 2.0f, &g_normalStrength },
+ { GROUP_MTL, L"Skin gloss: %0.2f", 0.0f, 1.0f, &g_glossSkin },
+ { GROUP_MTL, L"Eye gloss: %0.2f", 0.0f, 1.0f, &g_glossEye },
+
+#if 0
+ { GROUP_EYE, L"Iris radius src: %0.3f", 0.0f, 0.5f, &g_irisRadiusSource },
+ { GROUP_EYE, L"Iris radius dst: %0.3f", 0.0f, 0.5f, &g_irisRadiusDest },
+ { GROUP_EYE, L"Iris hardness: %0.0f", 0.0f, 100.0f, &g_irisEdgeHardness },
+ { GROUP_EYE, L"Iris dilation: %0.2f", 0.0f, 0.75f, &g_irisDilation },
+ { GROUP_MTL, L"Hair spec: %0.2f", 0.0f, 1.0f, &g_specReflectanceHair },
+ { GROUP_MTL, L"Hair gloss: %0.2f", 0.0f, 1.0f, &g_glossHair },
+#endif
+
+ { GROUP_DEEPSCATTER, L"DpSc intensity: %0.2f", 0.0f, 1.0f, &g_deepScatterIntensity },
+ { GROUP_DEEPSCATTER, L"DpSc radius (cm): %0.2f", 0.0f, 2.0f, &g_deepScatterRadius },
+ { GROUP_DEEPSCATTER, L"DpSc nrml ofs: %0.5f", -0.002f, 0.0f, &g_deepScatterNormalOffset },
+ { GROUP_DEEPSCATTER, L"DpSc shdw R (cm): %0.2f", 0.0f, 2.0f, &g_deepScatterShadowRadius },
+
+ { GROUP_SHADOW, L"VSM radius (cm): %0.2f", 0.0f, 1.0f, &g_vsmBlurRadius },
+#if 0
+ { GROUP_SHADOW, L"Shadow sharpen: %0.1f", 1.0f, 10.0f, &g_shadowSharpening },
+ { GROUP_SHADOW, L"VSM min var: %0.6f", 0.0f, 5e-4f, &g_vsmMinVariance },
+#endif
+
+#if 0
+ { GROUP_DEBUG, L"Debug0: %0.2f", 0.0f, 1.0f, &g_debugSlider0 },
+ { GROUP_DEBUG, L"Debug1: %0.2f", 0.0f, 1.0f, &g_debugSlider1 },
+ { GROUP_DEBUG, L"Debug2: %0.2f", 0.0f, 1.0f, &g_debugSlider2 },
+ { GROUP_DEBUG, L"Debug3: %0.2f", 0.0f, 1.0f, &g_debugSlider3 },
+#endif
+};
+
+static const int g_sliderStepsDefault = 100;
+
+void InitUI()
+{
+ g_HUD.Init(&g_DialogResourceManager);
+ g_HUD.SetBackgroundColors(D3DCOLOR_ARGB(128, 0, 0, 0));
+ g_HUD.SetCallback(&OnGUIEvent);
+
+ // Hard-coded HUD layout
+
+ static const int ITEM_HEIGHT = 20;
+ static const int ITEM_DELTA = ITEM_HEIGHT + 2;
+ static const int GROUP_DELTA = ITEM_DELTA;
+ static const int ITEM_WIDTH = 170;
+ static const int ITEM_LEFT = 15;
+
+ int iY = 0;
+
+ // About button
+ g_HUD.AddButton(IDC_ABOUT, L"About FaceWorks", ITEM_LEFT, iY += ITEM_DELTA, ITEM_WIDTH, ITEM_HEIGHT);
+
+ // Add combo box for scene selection
+
+ iY += GROUP_DELTA;
+
+ g_HUD.AddStatic(IDC_SCENE, L"Model", ITEM_LEFT, iY += ITEM_DELTA, ITEM_WIDTH, ITEM_HEIGHT);
+
+ CDXUTComboBox * pComboBoxScene = nullptr;
+ g_HUD.AddComboBox(IDC_SCENE, ITEM_LEFT, iY += ITEM_DELTA, ITEM_WIDTH, ITEM_HEIGHT, 0, false, &pComboBoxScene);
+ pComboBoxScene->AddItem(L"Digital Ira", &g_sceneDigitalIra);
+ pComboBoxScene->AddItem(L"LPS Head", &g_sceneLPSHead);
+ pComboBoxScene->AddItem(L"Warrior Head", &g_sceneWarriorHead);
+ pComboBoxScene->AddItem(L"Hand", &g_sceneHand);
+ pComboBoxScene->AddItem(L"Dragon", &g_sceneDragon);
+ pComboBoxScene->AddItem(L"Manjaladon", &g_sceneManjaladon);
+ pComboBoxScene->AddItem(L"Test", &g_sceneTest);
+ pComboBoxScene->SetSelectedByIndex(0);
+
+ // Add combo box for background selection
+
+ g_HUD.AddStatic(IDC_SCENE, L"Background", ITEM_LEFT, iY += ITEM_DELTA, ITEM_WIDTH, ITEM_HEIGHT);
+
+ CDXUTComboBox * pComboBoxBkgnd = nullptr;
+ g_HUD.AddComboBox(IDC_BKGND, ITEM_LEFT, iY += ITEM_DELTA, ITEM_WIDTH, ITEM_HEIGHT, 0, false, &pComboBoxBkgnd);
+ pComboBoxBkgnd->AddItem(L"Black", &g_bkgndBlack);
+ pComboBoxBkgnd->AddItem(L"Charcoal", &g_bkgndCharcoal);
+ pComboBoxBkgnd->AddItem(L"Forest", &g_bkgndForest);
+ pComboBoxBkgnd->AddItem(L"Night", &g_bkgndNight);
+ pComboBoxBkgnd->AddItem(L"Tunnel", &g_bkgndTunnel);
+ pComboBoxBkgnd->SetSelectedByIndex(1);
+
+ // Add combo box for SSS method
+
+ g_HUD.AddStatic(IDC_SSS_METHOD, L"SSS Method", ITEM_LEFT, iY += ITEM_DELTA, ITEM_WIDTH, ITEM_HEIGHT);
+
+ CDXUTComboBox * pComboBoxRMethod = nullptr;
+ g_HUD.AddComboBox(IDC_SSS_METHOD, ITEM_LEFT, iY += ITEM_DELTA, ITEM_WIDTH, ITEM_HEIGHT, 0, false, &pComboBoxRMethod);
+
+ static const wchar_t * s_aStrRMethod[] =
+ {
+ L"None", // RM_None
+ L"SSS", // RM_SSS
+ L"SSS+Deep", // RM_SSSAndDeep
+ L"View Curvature", // RM_ViewCurvature
+ L"View Thickness", // RM_ViewThickness
+ };
+ static_assert(dim(s_aStrRMethod) == RM_Max, "Size of s_aStrRMethod must match the number of entries in enum RM");
+
+ for (int i = 0; i < RM_Max; ++i)
+ {
+ pComboBoxRMethod->AddItem(s_aStrRMethod[i], nullptr);
+ }
+
+ pComboBoxRMethod->SetSelectedByIndex(g_renderMethod);
+
+ // Add sliders
+
+ std::wstring str;
+ int groupCur = -1;
+
+ for (int i = 0; i < dim(g_aSlider); ++i)
+ {
+ const Slider & slider = g_aSlider[i];
+
+ if (slider.m_group != groupCur)
+ {
+ iY += GROUP_DELTA;
+ groupCur = slider.m_group;
+ }
+
+ str = StrPrintf(slider.m_strCaption, *slider.m_pValue);
+ int steps = slider.m_steps ? slider.m_steps : g_sliderStepsDefault;
+ int sliderValue = int((*slider.m_pValue - slider.m_min) / (slider.m_max - slider.m_min) * steps);
+
+ g_HUD.AddStatic(IDC_SLIDER_BASE + i, str.c_str(), ITEM_LEFT, iY += ITEM_DELTA, ITEM_WIDTH, ITEM_HEIGHT);
+ g_HUD.AddSlider(IDC_SLIDER_BASE + i, ITEM_LEFT, iY += ITEM_DELTA, ITEM_WIDTH, ITEM_HEIGHT, 0, steps, sliderValue);
+ }
+
+ iY += GROUP_DELTA;
+
+ g_HUD.AddButton(IDC_CAMERA_WIDE, L"Wide shot", ITEM_LEFT, iY += ITEM_DELTA, ITEM_WIDTH, ITEM_HEIGHT);
+ g_HUD.AddButton(IDC_CAMERA_CLOSE, L"Close shot", ITEM_LEFT, iY += ITEM_DELTA, ITEM_WIDTH, ITEM_HEIGHT);
+ g_HUD.AddButton(IDC_CAMERA_EYE, L"Eyeball shot", ITEM_LEFT, iY += ITEM_DELTA, ITEM_WIDTH, ITEM_HEIGHT);
+
+ iY += GROUP_DELTA;
+
+ g_HUD.AddStatic(IDC_VIEW_BUFFER, L"View buffer", ITEM_LEFT, iY += ITEM_DELTA, ITEM_WIDTH, ITEM_HEIGHT);
+
+ CDXUTComboBox * pComboBoxViewBuffer = nullptr;
+ g_HUD.AddComboBox(IDC_VIEW_BUFFER, ITEM_LEFT, iY += ITEM_DELTA, ITEM_WIDTH, ITEM_HEIGHT, 0, false, &pComboBoxViewBuffer);
+
+ static const wchar_t * s_aStrViewBuffer[] =
+ {
+ L"None", // VIEWBUF_None
+ L"Shadow Map", // VIEWBUF_ShadowMap
+ };
+ static_assert(dim(s_aStrViewBuffer) == VIEWBUF_Max, "Size of s_aStrViewBuffer must match the number of entries in enum VIEWBUF");
+
+ for (int i = 0; i < VIEWBUF_Max; ++i)
+ {
+ pComboBoxViewBuffer->AddItem(s_aStrViewBuffer[i], nullptr);
+ }
+
+ pComboBoxViewBuffer->SetSelectedByIndex(g_viewbuf);
+}
+
+void CALLBACK OnGUIEvent(UINT nEvent, int nControlID, CDXUTControl * /*pControl*/, void * /*pUserContext*/)
+{
+ switch (nControlID)
+ {
+ case IDC_ABOUT:
+ MessageBoxA(DXUTGetHWND(), GFSDK_FaceWorks_GetBuildInfo(), "NVIDIA FaceWorks", MB_ICONINFORMATION);
+ break;
+
+ case IDC_SCENE:
+ g_pSceneCur = static_cast<CScene *>(g_HUD.GetComboBox(nControlID)->GetSelectedData());
+ break;
+
+ case IDC_BKGND:
+ g_pBkgndCur = static_cast<CBackground *>(g_HUD.GetComboBox(nControlID)->GetSelectedData());
+ break;
+
+ case IDC_SSS_METHOD:
+ {
+ int i = g_HUD.GetComboBox(nControlID)->GetSelectedIndex();
+ assert(i >= 0 && i < RM_Max);
+ g_renderMethod = RM(i);
+ }
+ break;
+
+ case IDC_CAMERA_WIDE:
+ {
+ XMVECTOR posLookAt = XMLoadFloat3(&g_sceneDigitalIra.m_meshHead.m_posCenter);
+ XMVECTOR posCamera = posLookAt + XMVectorSet(0.0f, 0.0f, 150.0f, 0.0f);
+ g_sceneDigitalIra.Camera()->SetViewParams(posCamera, posLookAt);
+ }
+ break;
+
+ case IDC_CAMERA_CLOSE:
+ {
+ XMVECTOR posLookAt = XMLoadFloat3(&g_sceneDigitalIra.m_meshHead.m_posCenter);
+ XMVECTOR posCamera = posLookAt + XMVectorSet(0.0f, 0.0f, 60.0f, 0.0f);
+ g_sceneDigitalIra.Camera()->SetViewParams(posCamera, posLookAt);
+ }
+ break;
+
+ case IDC_CAMERA_EYE:
+ {
+ XMVECTOR posLookAt = XMLoadFloat3(&g_sceneDigitalIra.m_meshEyeL.m_posCenter);
+ XMVECTOR posCamera = posLookAt + XMVectorSet(0.0f, 0.0f, 10.0f, 0.0f);
+ g_sceneDigitalIra.Camera()->SetViewParams(posCamera, posLookAt);
+ }
+ break;
+
+ case IDC_VIEW_BUFFER:
+ {
+ int i = g_HUD.GetComboBox(nControlID)->GetSelectedIndex();
+ assert(i >= 0 && i < VIEWBUF_Max);
+ g_viewbuf = VIEWBUF(i);
+ }
+ break;
+
+ default:
+ if (nControlID >= IDC_SLIDER_BASE &&
+ nEvent == EVENT_SLIDER_VALUE_CHANGED)
+ {
+ const Slider & slider = g_aSlider[nControlID - IDC_SLIDER_BASE];
+
+ int sliderValue = g_HUD.GetSlider(nControlID)->GetValue();
+ int steps = slider.m_steps ? slider.m_steps : g_sliderStepsDefault;
+ *slider.m_pValue = slider.m_min + float(sliderValue) / float(steps) * (slider.m_max - slider.m_min);
+ g_HUD.GetStatic(nControlID)->SetText(StrPrintf(slider.m_strCaption, *slider.m_pValue).c_str());
+ }
+ break;
+ }
+}
+
+void UpdateSliders()
+{
+ for (int i = 0; i < dim(g_aSlider); ++i)
+ {
+ const Slider & slider = g_aSlider[i];
+
+ int steps = slider.m_steps ? slider.m_steps : g_sliderStepsDefault;
+ int sliderValue = int((*slider.m_pValue - slider.m_min) / (slider.m_max - slider.m_min) * steps);
+ g_HUD.GetSlider(IDC_SLIDER_BASE + i)->SetValue(sliderValue);
+ g_HUD.GetStatic(IDC_SLIDER_BASE + i)->SetText(StrPrintf(slider.m_strCaption, *slider.m_pValue).c_str());
+ }
+}
+
+LRESULT CALLBACK MsgProc(
+ HWND hWnd,
+ UINT uMsg,
+ WPARAM wParam, LPARAM lParam,
+ bool * pbNoFurtherProcessing,
+ void * /*pUserContext*/)
+{
+ // Pass messages to dialog resource manager so GUI state is updated correctly
+ *pbNoFurtherProcessing = g_DialogResourceManager.MsgProc(hWnd, uMsg, wParam, lParam);
+ if (*pbNoFurtherProcessing)
+ return 0;
+
+ // Give the dialogs a chance to handle the message first
+ *pbNoFurtherProcessing = g_HUD.MsgProc(hWnd, uMsg, wParam, lParam);
+ if (*pbNoFurtherProcessing)
+ return 0;
+
+ if (g_pSceneCur)
+ g_pSceneCur->Camera()->HandleMessages(hWnd, uMsg, wParam, lParam);
+
+ return 0;
+}
+
+void CALLBACK OnKeyboard(UINT nChar, bool bKeyDown, bool /*bAltDown*/, void * /*pUserContext*/)
+{
+ if (!bKeyDown)
+ return;
+
+ switch (nChar)
+ {
+ case VK_F1:
+ g_ShowHelp = !g_ShowHelp;
+ break;
+
+ case VK_F2:
+ g_pSceneCur = &g_sceneDigitalIra;
+ g_HUD.GetComboBox(IDC_SCENE)->SetSelectedByData(&g_sceneDigitalIra);
+ break;
+
+ case VK_F3:
+ g_pSceneCur = &g_sceneLPSHead;
+ g_HUD.GetComboBox(IDC_SCENE)->SetSelectedByData(&g_sceneLPSHead);
+ break;
+
+ case VK_F4:
+ g_pSceneCur = &g_sceneWarriorHead;
+ g_HUD.GetComboBox(IDC_SCENE)->SetSelectedByData(&g_sceneWarriorHead);
+ break;
+
+ case VK_F5:
+ g_pSceneCur = &g_sceneHand;
+ g_HUD.GetComboBox(IDC_SCENE)->SetSelectedByData(&g_sceneHand);
+ break;
+
+ case VK_F6:
+ g_pSceneCur = &g_sceneDragon;
+ g_HUD.GetComboBox(IDC_SCENE)->SetSelectedByData(&g_sceneDragon);
+ break;
+
+ case VK_F7:
+ g_pSceneCur = &g_sceneManjaladon;
+ g_HUD.GetComboBox(IDC_SCENE)->SetSelectedByData(&g_sceneManjaladon);
+ break;
+
+ case VK_F8:
+ g_pSceneCur = &g_sceneTest;
+ g_HUD.GetComboBox(IDC_SCENE)->SetSelectedByData(&g_sceneTest);
+ break;
+
+ case 'G':
+ g_ShowGUI = !g_ShowGUI;
+ break;
+
+ case 'T':
+ g_ShowText = !g_ShowText;
+ break;
+
+ case 'F':
+ g_bWireframe = !g_bWireframe;
+ break;
+
+ case 'P':
+ g_bShowPerf = !g_bShowPerf;
+ break;
+
+ case 'C':
+ g_bCopyPerfToClipboard = true;
+ break;
+
+ case 'Y':
+ g_bTessellation = !g_bTessellation;
+ break;
+
+ case 'R':
+ g_shdmgr.DiscardRuntimeCompiledShaders();
+ break;
+
+ case VK_ESCAPE:
+ PostQuitMessage(0);
+ break;
+
+ default:
+ if (nChar >= '1' && nChar < '1' + RM_Max)
+ {
+ g_renderMethod = RM(nChar - '1');
+ g_HUD.GetComboBox(IDC_SSS_METHOD)->SetSelectedByIndex(g_renderMethod);
+ }
+ break;
+ }
+}
+
+void RenderText()
+{
+ g_pTxtHelper->Begin();
+ g_pTxtHelper->SetInsertionPos(2, 0);
+ g_pTxtHelper->SetForegroundColor(XMFLOAT4(0.0f, 1.0f, 0.0f, 1.0f));
+
+ const DXGI_SURFACE_DESC * pBackBufferDesc = DXUTGetDXGIBackBufferSurfaceDesc();
+ g_pTxtHelper->DrawTextLine(
+ StrPrintf(
+ L"D3D11, %0.2f ms, vsync %s, %dx%d, %s, MS%d Q%d",
+ 1000.0f / DXUTGetFPS(),
+ DXUTIsVsyncEnabled() ? L"on" : L"off",
+ pBackBufferDesc->Width,
+ pBackBufferDesc->Height,
+ DXUTDXGIFormatToString(pBackBufferDesc->Format, false),
+ pBackBufferDesc->SampleDesc.Count,
+ pBackBufferDesc->SampleDesc.Quality).c_str());
+
+ g_pTxtHelper->DrawTextLine(DXUTGetDeviceStats());
+
+ if (g_ShowHelp)
+ {
+ static const int HELP_HEIGHT = 300;
+ UINT nBackBufferHeight = DXUTGetDXGIBackBufferSurfaceDesc()->Height;
+ g_pTxtHelper->SetInsertionPos(2, nBackBufferHeight - HELP_HEIGHT);
+
+ g_pTxtHelper->DrawTextLine(
+ L"--Controls--\n"
+ L"Rotate Camera: Left Mouse\n"
+ L"Zoom Camera: Right Mouse or Mouse Wheel\n"
+ L"Move Camera: Middle Mouse\n"
+ L"Reset Camera: Home\n"
+ L"Toggle Wireframe: F\n"
+ L"Toggle GUI: G\n"
+ L"Toggle Text: T\n"
+ L"Toggle Perf Readouts: P\n"
+ L"Copy Perf To Clipboard: C\n"
+ L"Toggle Tessellation: Y\n"
+ L"Reload Runtime-Compiled Shaders: R\n"
+ L"Toggle Help: F1\n"
+ L"Quit: Esc\n"
+ );
+ }
+ else
+ {
+ g_pTxtHelper->DrawTextLine(L"Press F1 for help" );
+ }
+
+ if (g_bShowPerf)
+ {
+ static const wchar_t * s_aStrRMethod[] =
+ {
+ L"No SSS", // RM_None
+ L"SSS", // RM_SSS
+ L"SSS + Deep Scattering", // RM_SSSAndDeep
+ L"Curvature", // RM_ViewCurvature
+ L"View Thickness", // RM_ViewThickness
+ };
+ static_assert(dim(s_aStrRMethod) == RM_Max, "Size of s_aStrRMethod must match the number of entries in enum RM");
+
+ g_pTxtHelper->SetInsertionPos(2, 65);
+ g_pTxtHelper->DrawTextLine(
+ StrPrintf(
+ L"---Perf - %s---\n"
+ L"Shadow map: %0.2f ms\n"
+ L"Skin: %0.2f ms\n"
+ L"Eyes: %0.2f ms\n"
+ L"Sky/UI: %0.2f ms\n"
+ L"Total GPU frame time: %0.2f ms\n",
+ s_aStrRMethod[g_renderMethod],
+ g_gpuProfiler.DtAvg(GTS_ShadowMap) * 1000.0f,
+ g_gpuProfiler.DtAvg(GTS_Skin) * 1000.0f,
+ g_gpuProfiler.DtAvg(GTS_Eyes) * 1000.0f,
+ g_gpuProfiler.DtAvg(GTS_EndFrame) * 1000.0f,
+ g_gpuProfiler.GPUFrameTimeAvg() * 1000.0f
+ ).c_str());
+ }
+
+ if (g_bCopyPerfToClipboard)
+ {
+ std::wstring strToCopy;
+ strToCopy = StrPrintf(
+ L"%0.2f\t%0.2f\t%0.2f",
+ g_gpuProfiler.DtAvg(GTS_ShadowMap) * 1000.0f,
+ g_gpuProfiler.DtAvg(GTS_Skin) * 1000.0f,
+ g_gpuProfiler.DtAvg(GTS_Eyes) * 1000.0f
+ );
+
+ if (OpenClipboard(DXUTGetHWND()))
+ {
+ EmptyClipboard();
+ size_t cbString = sizeof(wchar_t) * (strToCopy.size() + 1);
+ HGLOBAL clipbuffer = GlobalAlloc(GMEM_DDESHARE, cbString);
+ if (clipbuffer) {
+ wchar_t * buffer = static_cast<wchar_t *>(GlobalLock(clipbuffer));
+ if (buffer) {
+ memcpy(buffer, strToCopy.c_str(), cbString);
+ GlobalUnlock(clipbuffer);
+ SetClipboardData(CF_UNICODETEXT, clipbuffer);
+ }
+ }
+ CloseClipboard();
+ }
+
+ g_bCopyPerfToClipboard = false;
+ }
+
+ g_pTxtHelper->End();
+}
+
+void CopyTexture(
+ ID3D11DeviceContext * pCtx,
+ ID3D11ShaderResourceView * pSrvSrc,
+ ID3D11RenderTargetView * pRtvDest,
+ ID3D11DepthStencilView * pDsvDest,
+ const XMFLOAT4 & rectDest,
+ const XMFLOAT4X4 * pMatTransformColor /* = nullptr */)
+{
+ D3D11_VIEWPORT viewport =
+ {
+ rectDest.x, rectDest.y, // left, top
+ rectDest.z, rectDest.w, // width, height
+ 0.0f, 1.0f, // min/max depth
+ };
+
+ pCtx->RSSetViewports(1, &viewport);
+ pCtx->OMSetRenderTargets(1, &pRtvDest, pDsvDest);
+
+ XMFLOAT4X4 matIdentity;
+ if (!pMatTransformColor)
+ {
+ pMatTransformColor = &matIdentity;
+ XMStoreFloat4x4(&matIdentity, XMMatrixIdentity());
+ }
+
+ g_shdmgr.BindCopy(pCtx, pSrvSrc, *pMatTransformColor);
+ g_meshFullscreen.Draw(pCtx);
+}
diff --git a/samples/d3d11/scenes.cpp b/samples/d3d11/scenes.cpp
new file mode 100644
index 0000000..05c6223
--- /dev/null
+++ b/samples/d3d11/scenes.cpp
@@ -0,0 +1,1079 @@
+//----------------------------------------------------------------------------------
+// File: FaceWorks/samples/sample_d3d11/scenes.cpp
+// 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.
+//
+//----------------------------------------------------------------------------------
+
+#include "scenes.h"
+#include "shaders/resources.h"
+
+#include <algorithm>
+
+#include <DirectXMath.h>
+
+#include <DXUT/Core/DXUT.h>
+#include <DXUT/Optional/SDKmisc.h>
+
+using namespace std;
+using namespace DirectX;
+
+float g_normalStrength = 1.0;
+float g_glossSkin = 0.35f;
+float g_glossEye = 0.9f;
+float g_specReflectanceSkinDefault = 0.05f;
+float g_specReflectanceEye = 0.05f;
+float g_rgbDeepScatterEye[3] = { 1.0f, 0.3f, 0.3f };
+float g_irisRadiusSource = 0.200f; // Radius of iris in iris texture (in UV units)
+float g_irisRadiusDest = 0.205f; // Radius of iris in schlera texture (in UV units)
+float g_irisEdgeHardness = 30.0f; // Controls hardness/softness of iris edge
+float g_irisDilation = 0.0f; // How much the iris is dilated
+float g_specReflectanceHair = 0.05f;
+float g_glossHair = 0.25f;
+
+
+
+int GetTextureSize(ID3D11ShaderResourceView * pSrv)
+{
+ ID3D11Texture2D * pTex;
+ pSrv->GetResource(reinterpret_cast<ID3D11Resource **>(&pTex));
+ D3D11_TEXTURE2D_DESC texDesc;
+ pTex->GetDesc(&texDesc);
+ int texSize = (texDesc.Width + texDesc.Height) / 2;
+ SAFE_RELEASE(pTex);
+ return texSize;
+}
+
+ID3D11ShaderResourceView * Create1x1Texture(float r, float g, float b, bool linear = false)
+{
+ // Convert floats to 8-bit format
+
+ unsigned char rgba[4] =
+ {
+ static_cast<unsigned char>(min(max(r, 0.0f), 1.0f) * 255.0f + 0.5f),
+ static_cast<unsigned char>(min(max(g, 0.0f), 1.0f) * 255.0f + 0.5f),
+ static_cast<unsigned char>(min(max(b, 0.0f), 1.0f) * 255.0f + 0.5f),
+ 255
+ };
+
+ D3D11_TEXTURE2D_DESC texDesc =
+ {
+ 1, 1, 1, 1,
+ linear ? DXGI_FORMAT_R8G8B8A8_UNORM : DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
+ { 1, 0 },
+ D3D11_USAGE_DEFAULT,
+ D3D11_BIND_SHADER_RESOURCE,
+ 0, 0,
+ };
+
+ D3D11_SUBRESOURCE_DATA initialData = { rgba, 4, };
+
+ ID3D11Device * pDevice = DXUTGetD3D11Device();
+ ID3D11Texture2D * pTex = nullptr;
+ HRESULT hr;
+ V(pDevice->CreateTexture2D(&texDesc, &initialData, &pTex));
+
+ D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc =
+ {
+ texDesc.Format,
+ D3D11_SRV_DIMENSION_TEXTURE2D,
+ };
+ srvDesc.Texture2D.MipLevels = 1;
+
+ ID3D11ShaderResourceView * pSrv = nullptr;
+ V(pDevice->CreateShaderResourceView(pTex, &srvDesc, &pSrv));
+
+ SAFE_RELEASE(pTex);
+ return pSrv;
+}
+
+// CScene implementation
+
+CScene::~CScene() {}
+
+// CSceneDigitalIra implementation
+
+CSceneDigitalIra::CSceneDigitalIra()
+: m_meshHead(),
+ m_meshEyeL(),
+ m_meshEyeR(),
+ m_meshLashes(),
+ m_meshBrows(),
+ m_pSrvDiffuseHead(nullptr),
+ m_pSrvNormalHead(nullptr),
+ m_pSrvSpecHead(nullptr),
+ m_pSrvDeepScatterHead(nullptr),
+ m_pSrvDiffuseEyeSclera(nullptr),
+ m_pSrvNormalEyeSclera(nullptr),
+ m_pSrvDiffuseEyeIris(nullptr),
+ m_pSrvDiffuseLashes(nullptr),
+ m_pSrvDiffuseBrows(nullptr),
+ m_mtlHead(),
+ m_mtlEye(),
+ m_mtlLashes(),
+ m_mtlBrows(),
+ m_camera(),
+ m_normalHeadSize(0),
+ m_normalEyeSize(0)
+{
+}
+
+HRESULT CSceneDigitalIra::Init()
+{
+ HRESULT hr;
+ wchar_t strPath[MAX_PATH];
+ ID3D11Device * pDevice = DXUTGetD3D11Device();
+ ID3D11DeviceContext *pDeviceContext = DXUTGetD3D11DeviceContext();
+
+ // Load meshes
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"DigitalIra\\HumanHead.obj"));
+ V_RETURN(LoadObjMesh(strPath, pDevice, &m_meshHead));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"DigitalIra\\EyeL.obj"));
+ V_RETURN(LoadObjMesh(strPath, pDevice, &m_meshEyeL));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"DigitalIra\\EyeR.obj"));
+ V_RETURN(LoadObjMesh(strPath, pDevice, &m_meshEyeR));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"DigitalIra\\Lashes.obj"));
+ V_RETURN(LoadObjMesh(strPath, pDevice, &m_meshLashes));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"DigitalIra\\Brows.obj"));
+ V_RETURN(LoadObjMesh(strPath, pDevice, &m_meshBrows));
+
+ // Load textures
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"DigitalIra\\00_diffuse_albedo.bmp"));
+ V_RETURN(LoadTexture(strPath, pDevice, pDeviceContext, &m_pSrvDiffuseHead));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"DigitalIra\\00_specular_normal_tangent.bmp"));
+ V_RETURN(LoadTexture(strPath, pDevice, pDeviceContext, &m_pSrvNormalHead, LT_Mipmap | LT_Linear));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"DigitalIra\\00_specular_albedo.bmp"));
+ V_RETURN(LoadTexture(strPath, pDevice, pDeviceContext, &m_pSrvSpecHead));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"DigitalIra\\HumanHead_deepscatter.bmp"));
+ V_RETURN(LoadTexture(strPath, pDevice, pDeviceContext, &m_pSrvDeepScatterHead));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"DigitalIra\\sclera_col.bmp"));
+ V_RETURN(LoadTexture(strPath, pDevice, pDeviceContext, &m_pSrvDiffuseEyeSclera));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"DigitalIra\\eyeballNormalMap.bmp"));
+ V_RETURN(LoadTexture(strPath, pDevice, pDeviceContext, &m_pSrvNormalEyeSclera, LT_Mipmap | LT_Linear));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"DigitalIra\\iris.bmp"));
+ V_RETURN(LoadTexture(strPath, pDevice, pDeviceContext, &m_pSrvDiffuseEyeIris));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"DigitalIra\\lashes.dds"));
+ V_RETURN(LoadTexture(strPath, pDevice, pDeviceContext, &m_pSrvDiffuseLashes));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"DigitalIra\\brows.dds"));
+ V_RETURN(LoadTexture(strPath, pDevice, pDeviceContext, &m_pSrvDiffuseBrows));
+
+ // Set up materials
+
+ m_mtlHead.m_shader = SHADER_Skin;
+ m_mtlHead.m_aSrv[0] = m_pSrvDiffuseHead; m_mtlHead.m_textureSlots[0] = TEX_DIFFUSE0;
+ m_mtlHead.m_aSrv[1] = m_pSrvNormalHead; m_mtlHead.m_textureSlots[1] = TEX_NORMAL;
+ m_mtlHead.m_aSrv[2] = m_pSrvSpecHead; m_mtlHead.m_textureSlots[2] = TEX_SPEC;
+ m_mtlHead.m_aSrv[3] = m_pSrvDeepScatterHead; m_mtlHead.m_textureSlots[3] = TEX_DEEP_SCATTER_COLOR;
+ m_mtlHead.m_constants[0] = g_normalStrength;
+ m_mtlHead.m_constants[1] = g_glossSkin;
+
+ m_mtlEye.m_shader = SHADER_Eye;
+ m_mtlEye.m_aSrv[0] = m_pSrvDiffuseEyeSclera; m_mtlEye.m_textureSlots[0] = TEX_DIFFUSE0;
+ m_mtlEye.m_aSrv[1] = m_pSrvDiffuseEyeIris; m_mtlEye.m_textureSlots[1] = TEX_DIFFUSE1;
+ m_mtlEye.m_aSrv[2] = m_pSrvNormalEyeSclera; m_mtlEye.m_textureSlots[2] = TEX_NORMAL;
+ m_mtlEye.m_constants[0] = 0.05f; // normal strength
+ m_mtlEye.m_constants[1] = g_specReflectanceEye;
+ m_mtlEye.m_constants[2] = g_glossEye;
+ m_mtlEye.m_constants[4] = g_rgbDeepScatterEye[0];
+ m_mtlEye.m_constants[5] = g_rgbDeepScatterEye[1];
+ m_mtlEye.m_constants[6] = g_rgbDeepScatterEye[2];
+ m_mtlEye.m_constants[7] = 0.455f; // Radius of iris in iris texture (in UV units);
+ m_mtlEye.m_constants[8] = 0.230f; // Radius of iris in schlera texture (in UV units);
+ m_mtlEye.m_constants[9] = 30.0f; // Controls hardness/softness of iris edge;
+ m_mtlEye.m_constants[10] = 0.5f; // How much the iris is dilated;
+
+ m_mtlLashes.m_shader = SHADER_Hair;
+ m_mtlLashes.m_aSrv[0] = m_pSrvDiffuseLashes; m_mtlLashes.m_textureSlots[0] = TEX_DIFFUSE0;
+ m_mtlLashes.m_constants[0] = g_specReflectanceHair;
+ m_mtlLashes.m_constants[1] = g_glossHair;
+
+ m_mtlBrows.m_shader = SHADER_Hair;
+ m_mtlBrows.m_aSrv[0] = m_pSrvDiffuseBrows; m_mtlBrows.m_textureSlots[0] = TEX_DIFFUSE0;
+ m_mtlBrows.m_constants[0] = g_specReflectanceHair;
+ m_mtlBrows.m_constants[1] = g_glossHair;
+
+ // Set up camera to orbit around the head
+
+ XMVECTOR posLookAt = XMLoadFloat3(&m_meshHead.m_posCenter);
+ XMVECTOR posCamera = posLookAt + XMVectorSet(0.0f, 0.0f, 60.0f, 0.0f);
+ m_camera.SetViewParams(posCamera, posLookAt);
+
+ // Pull out normal map texture sizes for SSS mip level calculations
+
+ m_normalHeadSize = GetTextureSize(m_pSrvNormalHead);
+ m_normalEyeSize = GetTextureSize(m_pSrvNormalEyeSclera);
+
+ return S_OK;
+}
+
+void CSceneDigitalIra::Release()
+{
+ m_meshHead.Release();
+ m_meshEyeL.Release();
+ m_meshEyeR.Release();
+ m_meshLashes.Release();
+ m_meshBrows.Release();
+
+ SAFE_RELEASE(m_pSrvDiffuseHead);
+ SAFE_RELEASE(m_pSrvNormalHead);
+ SAFE_RELEASE(m_pSrvSpecHead);
+ SAFE_RELEASE(m_pSrvDeepScatterHead);
+
+ SAFE_RELEASE(m_pSrvDiffuseEyeSclera);
+ SAFE_RELEASE(m_pSrvNormalEyeSclera);
+ SAFE_RELEASE(m_pSrvDiffuseEyeIris);
+
+ SAFE_RELEASE(m_pSrvDiffuseLashes);
+ SAFE_RELEASE(m_pSrvDiffuseBrows);
+}
+
+CBaseCamera* CSceneDigitalIra::Camera()
+{
+ return &m_camera;
+}
+
+void CSceneDigitalIra::GetBounds(XMFLOAT3 * pPosMin, XMFLOAT3 * pPosMax)
+{
+ assert(pPosMin);
+ assert(pPosMax);
+
+ *pPosMin = m_meshHead.m_posMin;
+ *pPosMax = m_meshHead.m_posMax;
+}
+
+void CSceneDigitalIra::GetMeshesToDraw(std::vector<MeshToDraw> * pMeshesToDraw)
+{
+ assert(pMeshesToDraw);
+
+ // Allow updating normal strength and gloss in real-time
+ m_mtlHead.m_constants[0] = g_normalStrength;
+ m_mtlHead.m_constants[1] = g_glossSkin;
+ m_mtlEye.m_constants[2] = g_glossEye;
+ m_mtlLashes.m_constants[0] = g_specReflectanceHair;
+ m_mtlLashes.m_constants[1] = g_glossHair;
+ m_mtlBrows.m_constants[0] = g_specReflectanceHair;
+ m_mtlBrows.m_constants[1] = g_glossHair;
+
+ // Generate draw records
+
+ MeshToDraw aMtd[] =
+ {
+ { &m_mtlHead, &m_meshHead, m_normalHeadSize, m_meshHead.m_uvScale, },
+ { &m_mtlEye, &m_meshEyeL, m_normalEyeSize, m_meshEyeL.m_uvScale, },
+ { &m_mtlEye, &m_meshEyeR, m_normalEyeSize, m_meshEyeR.m_uvScale, },
+ { &m_mtlLashes, &m_meshLashes, },
+ { &m_mtlBrows, &m_meshBrows, },
+ };
+
+ pMeshesToDraw->assign(&aMtd[0], &aMtd[dim(aMtd)]);
+}
+
+
+
+// CSceneTest implementation
+
+CSceneTest::CSceneTest()
+: m_meshPlanes(),
+ m_meshShadower(),
+ m_aMeshSpheres(),
+ m_pSrvDiffuse(nullptr),
+ m_pSrvNormalFlat(nullptr),
+ m_pSrvSpec(nullptr),
+ m_pSrvDeepScatter(nullptr),
+ m_mtl(),
+ m_camera()
+{
+}
+
+HRESULT CSceneTest::Init()
+{
+ HRESULT hr;
+ wchar_t strPath[MAX_PATH];
+ ID3D11Device * pDevice = DXUTGetD3D11Device();
+
+ // Load meshes
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"testPlanes.obj"));
+ V_RETURN(LoadObjMesh(strPath, pDevice, &m_meshPlanes));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"testShadowCaster.obj"));
+ V_RETURN(LoadObjMesh(strPath, pDevice, &m_meshShadower));
+
+ static const wchar_t * aStrSphereNames[] =
+ {
+ L"testSphere1mm.obj",
+ L"testSphere2mm.obj",
+ L"testSphere5mm.obj",
+ L"testSphere1cm.obj",
+ L"testSphere2cm.obj",
+ L"testSphere5cm.obj",
+ L"testSphere10cm.obj",
+ };
+ static_assert(dim(aStrSphereNames) == dim(m_aMeshSpheres), "dimension mismatch between array aStrSphereNames and m_aMeshSpheres");
+
+ for (int i = 0; i < dim(m_aMeshSpheres); ++i)
+ {
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), aStrSphereNames[i]));
+ V_RETURN(LoadObjMesh(strPath, pDevice, &m_aMeshSpheres[i]));
+ }
+
+ // Create 1x1 textures
+
+ m_pSrvDiffuse = Create1x1Texture(1.0f, 1.0f, 1.0f);
+ m_pSrvNormalFlat = Create1x1Texture(0.5f, 0.5f, 1.0f, true);
+ m_pSrvSpec = Create1x1Texture(0.05f, 0.05f, 0.05f, true);
+ m_pSrvDeepScatter = Create1x1Texture(1.0f, 0.25f, 0.0f);
+
+ // Set up material
+
+ m_mtl.m_shader = SHADER_Skin;
+ m_mtl.m_aSrv[0] = m_pSrvDiffuse; m_mtl.m_textureSlots[0] = TEX_DIFFUSE0;
+ m_mtl.m_aSrv[1] = m_pSrvNormalFlat; m_mtl.m_textureSlots[1] = TEX_NORMAL;
+ m_mtl.m_aSrv[2] = m_pSrvSpec; m_mtl.m_textureSlots[2] = TEX_SPEC;
+ m_mtl.m_aSrv[2] = m_pSrvDeepScatter; m_mtl.m_textureSlots[3] = TEX_DEEP_SCATTER_COLOR;
+ m_mtl.m_constants[0] = g_normalStrength;
+ m_mtl.m_constants[1] = g_glossSkin;
+
+ // Set up camera in a default location
+
+ XMFLOAT3 posMin, posMax;
+ GetBounds(&posMin, &posMax);
+ XMVECTOR posLookAt = 0.5f * (XMLoadFloat3(&posMin) + XMLoadFloat3(&posMax));
+ XMVECTOR posCamera = posLookAt + XMVectorSet(0.0f, 0.0f, 60.0f, 0.0f);
+ m_camera.SetViewParams(posCamera, posLookAt);
+
+ // Adjust camera speed
+ m_camera.SetScalers(0.005f, 10.0f);
+
+ return S_OK;
+}
+
+void CSceneTest::Release()
+{
+ m_meshPlanes.Release();
+ m_meshShadower.Release();
+
+ for (int i = 0; i < dim(m_aMeshSpheres); ++i)
+ m_aMeshSpheres[i].Release();
+
+ SAFE_RELEASE(m_pSrvDiffuse);
+ SAFE_RELEASE(m_pSrvNormalFlat);
+ SAFE_RELEASE(m_pSrvSpec);
+ SAFE_RELEASE(m_pSrvDeepScatter);
+}
+
+CBaseCamera* CSceneTest::Camera()
+{
+ return &m_camera;
+}
+
+void CSceneTest::GetBounds(XMFLOAT3 * pPosMin, XMFLOAT3 * pPosMax)
+{
+ assert(pPosMin);
+ assert(pPosMax);
+
+ XMVECTOR posMin = XMLoadFloat3(&m_meshPlanes.m_posMin);
+ XMVECTOR posMax = XMLoadFloat3(&m_meshPlanes.m_posMax);
+
+ posMin = XMVectorMin(posMin, XMLoadFloat3(&m_meshShadower.m_posMin));
+ posMax = XMVectorMax(posMax, XMLoadFloat3(&m_meshShadower.m_posMax));
+
+ for (int i = 0; i < dim(m_aMeshSpheres); ++i)
+ {
+ posMin = XMVectorMin(posMin, XMLoadFloat3(&m_aMeshSpheres[i].m_posMin));
+ posMax = XMVectorMax(posMax, XMLoadFloat3(&m_aMeshSpheres[i].m_posMax));
+ }
+
+ XMStoreFloat3(pPosMin, posMin);
+ XMStoreFloat3(pPosMax, posMax);
+}
+
+void CSceneTest::GetMeshesToDraw(std::vector<MeshToDraw> * pMeshesToDraw)
+{
+ assert(pMeshesToDraw);
+
+ // Allow updating normal strength and gloss in real-time
+ m_mtl.m_constants[0] = g_normalStrength;
+ m_mtl.m_constants[1] = g_glossSkin;
+
+ // Generate draw records
+
+ MeshToDraw aMtd[] =
+ {
+ { &m_mtl, &m_meshShadower, 0, 1.0f, },
+ { &m_mtl, &m_meshPlanes, 0, 1.0f, },
+ };
+ pMeshesToDraw->assign(&aMtd[0], &aMtd[dim(aMtd)]);
+
+ for (int i = 0; i < dim(m_aMeshSpheres); ++i)
+ {
+ MeshToDraw mtd = { &m_mtl, &m_aMeshSpheres[i], 0, 1.0f };
+ pMeshesToDraw->push_back(mtd);
+ }
+}
+
+
+
+// CSceneHand implementation
+
+CSceneHand::CSceneHand()
+: m_meshHand(),
+ m_pSrvDiffuse(nullptr),
+ m_pSrvNormalFlat(nullptr),
+ m_pSrvSpec(nullptr),
+ m_pSrvDeepScatter(nullptr),
+ m_mtl(),
+ m_camera()
+{
+}
+
+HRESULT CSceneHand::Init()
+{
+ HRESULT hr;
+ wchar_t strPath[MAX_PATH];
+ ID3D11Device * pDevice = DXUTGetD3D11Device();
+
+ // Load meshes
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"hand01.obj"));
+ V_RETURN(LoadObjMesh(strPath, pDevice, &m_meshHand));
+
+ // Create 1x1 textures
+
+ m_pSrvDiffuse = Create1x1Texture(0.773f, 0.540f, 0.442f); // caucasian skin color
+ m_pSrvNormalFlat = Create1x1Texture(0.5f, 0.5f, 1.0f, true);
+ m_pSrvSpec = Create1x1Texture(0.05f, 0.05f, 0.05f, true);
+ m_pSrvDeepScatter = Create1x1Texture(1.0f, 0.25f, 0.0f);
+
+ // Set up material
+
+ m_mtl.m_shader = SHADER_Skin;
+ m_mtl.m_aSrv[0] = m_pSrvDiffuse; m_mtl.m_textureSlots[0] = TEX_DIFFUSE0;
+ m_mtl.m_aSrv[1] = m_pSrvNormalFlat; m_mtl.m_textureSlots[1] = TEX_NORMAL;
+ m_mtl.m_aSrv[2] = m_pSrvSpec; m_mtl.m_textureSlots[2] = TEX_SPEC;
+ m_mtl.m_aSrv[3] = m_pSrvDeepScatter; m_mtl.m_textureSlots[3] = TEX_DEEP_SCATTER_COLOR;
+ m_mtl.m_constants[0] = g_normalStrength;
+ m_mtl.m_constants[1] = g_glossSkin;
+
+ // Set up camera to orbit around the hand
+
+ XMVECTOR posLookAt = XMLoadFloat3(&m_meshHand.m_posCenter);
+ XMVECTOR posCamera = posLookAt + XMVectorSet(0.0f, 0.0f, 60.0f, 0.0f);
+ m_camera.SetViewParams(posCamera, posLookAt);
+
+ return S_OK;
+}
+
+void CSceneHand::Release()
+{
+ m_meshHand.Release();
+
+ SAFE_RELEASE(m_pSrvDiffuse);
+ SAFE_RELEASE(m_pSrvNormalFlat);
+ SAFE_RELEASE(m_pSrvSpec);
+ SAFE_RELEASE(m_pSrvDeepScatter);
+}
+
+CBaseCamera* CSceneHand::Camera()
+{
+ return &m_camera;
+}
+
+void CSceneHand::GetBounds(XMFLOAT3 * pPosMin, XMFLOAT3 * pPosMax)
+{
+ assert(pPosMin);
+ assert(pPosMax);
+
+ *pPosMin = m_meshHand.m_posMin;
+ *pPosMax = m_meshHand.m_posMax;
+}
+
+void CSceneHand::GetMeshesToDraw(std::vector<MeshToDraw> * pMeshesToDraw)
+{
+ assert(pMeshesToDraw);
+
+ // Allow updating normal strength and gloss in real-time
+ m_mtl.m_constants[0] = g_normalStrength;
+ m_mtl.m_constants[1] = g_glossSkin;
+
+ // Generate draw records
+
+ MeshToDraw aMtd[] =
+ {
+ { &m_mtl, &m_meshHand, 0, 1.0f, },
+ };
+ pMeshesToDraw->assign(&aMtd[0], &aMtd[dim(aMtd)]);
+}
+
+
+
+// CSceneDragon implementation
+
+CSceneDragon::CSceneDragon()
+: m_meshDragon(),
+ m_pSrvDiffuse(nullptr),
+ m_pSrvNormal(nullptr),
+ m_pSrvSpec(nullptr),
+ m_pSrvDeepScatter(nullptr),
+ m_mtl(),
+ m_camera(),
+ m_normalSize(0)
+{
+}
+
+HRESULT CSceneDragon::Init()
+{
+ HRESULT hr;
+ wchar_t strPath[MAX_PATH];
+ ID3D11Device * pDevice = DXUTGetD3D11Device();
+ ID3D11DeviceContext *pDeviceContext = DXUTGetD3D11DeviceContext();
+
+ // Load meshes
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"Dragon\\Dragon_gdc2014_BindPose.obj"));
+ V_RETURN(LoadObjMesh(strPath, pDevice, &m_meshDragon));
+
+ // Load textures
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"Dragon\\Dragon_New_D.bmp"));
+ V_RETURN(LoadTexture(strPath, pDevice, pDeviceContext, &m_pSrvDiffuse));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"Dragon\\Dragon_New_N.bmp"));
+ V_RETURN(LoadTexture(strPath, pDevice, pDeviceContext, &m_pSrvNormal, LT_Mipmap | LT_Linear));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"Dragon\\Dragon_New_S.bmp"));
+ V_RETURN(LoadTexture(strPath, pDevice, pDeviceContext, &m_pSrvSpec));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"Dragon\\Dragon_Subsurface.bmp"));
+ V_RETURN(LoadTexture(strPath, pDevice, pDeviceContext, &m_pSrvDeepScatter));
+
+ // Set up materials
+
+ m_mtl.m_shader = SHADER_Skin;
+ m_mtl.m_aSrv[0] = m_pSrvDiffuse; m_mtl.m_textureSlots[0] = TEX_DIFFUSE0;
+ m_mtl.m_aSrv[1] = m_pSrvNormal; m_mtl.m_textureSlots[1] = TEX_NORMAL;
+ m_mtl.m_aSrv[2] = m_pSrvSpec; m_mtl.m_textureSlots[2] = TEX_SPEC;
+ m_mtl.m_aSrv[3] = m_pSrvDeepScatter; m_mtl.m_textureSlots[3] = TEX_DEEP_SCATTER_COLOR;
+ m_mtl.m_constants[0] = g_normalStrength;
+ m_mtl.m_constants[1] = g_glossSkin;
+
+ // Set up camera to orbit around the dragon
+
+ XMVECTOR posLookAt = XMLoadFloat3(&m_meshDragon.m_posCenter) + XMVectorSet(0.0f, 0.0f, 5.0f, 0.0f);
+ XMVECTOR posCamera = posLookAt + XMVectorSet(0.0f, 0.0f, 40.0f, 0.0f);
+ m_camera.SetViewParams(posCamera, posLookAt);
+
+ // Pull out normal map texture size for SSS mip level calculations
+
+ m_normalSize = GetTextureSize(m_pSrvNormal);
+
+ return S_OK;
+}
+
+void CSceneDragon::Release()
+{
+ m_meshDragon.Release();
+
+ SAFE_RELEASE(m_pSrvDiffuse);
+ SAFE_RELEASE(m_pSrvNormal);
+ SAFE_RELEASE(m_pSrvSpec);
+ SAFE_RELEASE(m_pSrvDeepScatter);
+}
+
+void CSceneDragon::GetBounds(XMFLOAT3 * pPosMin, XMFLOAT3 * pPosMax)
+{
+ assert(pPosMin);
+ assert(pPosMax);
+
+ *pPosMin = m_meshDragon.m_posMin;
+ *pPosMax = m_meshDragon.m_posMax;
+}
+
+void CSceneDragon::GetMeshesToDraw(std::vector<MeshToDraw> * pMeshesToDraw)
+{
+ assert(pMeshesToDraw);
+
+ // Allow updating normal strength and gloss in real-time
+ m_mtl.m_constants[0] = g_normalStrength;
+ m_mtl.m_constants[1] = g_glossSkin;
+
+ // Generate draw records
+
+ MeshToDraw aMtd[] =
+ {
+ { &m_mtl, &m_meshDragon, m_normalSize, m_meshDragon.m_uvScale, },
+ };
+ pMeshesToDraw->assign(&aMtd[0], &aMtd[dim(aMtd)]);
+}
+
+
+
+// CSceneLPSHead implementation
+
+CSceneLPSHead::CSceneLPSHead()
+: m_meshHead(),
+ m_pSrvDiffuseHead(nullptr),
+ m_pSrvNormalHead(nullptr),
+ m_pSrvSpecHead(nullptr),
+ m_pSrvDeepScatterHead(nullptr),
+ m_mtlHead(),
+ m_camera(),
+ m_normalHeadSize(0)
+{
+}
+
+HRESULT CSceneLPSHead::Init()
+{
+ HRESULT hr;
+ wchar_t strPath[MAX_PATH];
+ ID3D11Device * pDevice = DXUTGetD3D11Device();
+ ID3D11DeviceContext *pDeviceContext = DXUTGetD3D11DeviceContext();
+
+ // Load meshes
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"LPSHead\\head.obj"));
+ V_RETURN(LoadObjMesh(strPath, pDevice, &m_meshHead));
+
+ // Load textures
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"LPSHead\\lambertian.jpg"));
+ V_RETURN(LoadTexture(strPath, pDevice, pDeviceContext, &m_pSrvDiffuseHead));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"LPSHead\\normal.bmp"));
+ V_RETURN(LoadTexture(strPath, pDevice, pDeviceContext, &m_pSrvNormalHead, LT_Mipmap | LT_Linear));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"LPSHead\\deepscatter.bmp"));
+ V_RETURN(LoadTexture(strPath, pDevice, pDeviceContext, &m_pSrvDeepScatterHead));
+
+ // Create 1x1 spec texture
+
+ m_pSrvSpecHead = Create1x1Texture(
+ g_specReflectanceSkinDefault,
+ g_specReflectanceSkinDefault,
+ g_specReflectanceSkinDefault,
+ true);
+
+ // Set up materials
+
+ m_mtlHead.m_shader = SHADER_Skin;
+ m_mtlHead.m_aSrv[0] = m_pSrvDiffuseHead; m_mtlHead.m_textureSlots[0] = TEX_DIFFUSE0;
+ m_mtlHead.m_aSrv[1] = m_pSrvNormalHead; m_mtlHead.m_textureSlots[1] = TEX_NORMAL;
+ m_mtlHead.m_aSrv[2] = m_pSrvSpecHead; m_mtlHead.m_textureSlots[2] = TEX_SPEC;
+ m_mtlHead.m_aSrv[3] = m_pSrvDeepScatterHead; m_mtlHead.m_textureSlots[3] = TEX_DEEP_SCATTER_COLOR;
+ m_mtlHead.m_constants[0] = g_normalStrength;
+
+ // Set up camera to orbit around the head
+
+ XMVECTOR posLookAt = XMLoadFloat3(&m_meshHead.m_posCenter) + XMVectorSet(0.0f, 3.0f, 0.0f, 0.0f);
+ XMVECTOR posCamera = posLookAt + XMVectorSet(0.0f, 0.0f, 60.0f, 0.0f);
+ m_camera.SetViewParams(posCamera, posLookAt);
+
+ // Pull out normal map texture size for SSS mip level calculations
+
+ m_normalHeadSize = GetTextureSize(m_pSrvNormalHead);
+
+ return S_OK;
+}
+
+void CSceneLPSHead::Release()
+{
+ m_meshHead.Release();
+
+ SAFE_RELEASE(m_pSrvDiffuseHead);
+ SAFE_RELEASE(m_pSrvNormalHead);
+ SAFE_RELEASE(m_pSrvSpecHead);
+ SAFE_RELEASE(m_pSrvDeepScatterHead);
+}
+
+void CSceneLPSHead::GetBounds(XMFLOAT3 * pPosMin, XMFLOAT3 * pPosMax)
+{
+ assert(pPosMin);
+ assert(pPosMax);
+
+ *pPosMin = m_meshHead.m_posMin;
+ *pPosMax = m_meshHead.m_posMax;
+}
+
+void CSceneLPSHead::GetMeshesToDraw(std::vector<MeshToDraw> * pMeshesToDraw)
+{
+ assert(pMeshesToDraw);
+
+ // Allow updating normal strength and gloss in real-time
+ m_mtlHead.m_constants[0] = g_normalStrength;
+ m_mtlHead.m_constants[1] = g_glossSkin;
+
+ // Generate draw records
+
+ MeshToDraw aMtd[] =
+ {
+ { &m_mtlHead, &m_meshHead, m_normalHeadSize, m_meshHead.m_uvScale, },
+ };
+
+ pMeshesToDraw->assign(&aMtd[0], &aMtd[dim(aMtd)]);
+}
+
+
+
+// CSceneManjaladon implementation
+
+CSceneManjaladon::CSceneManjaladon()
+: m_meshManjaladon(),
+ m_pSrvDiffuse(nullptr),
+ m_pSrvNormal(nullptr),
+ m_pSrvSpec(nullptr),
+ m_pSrvDeepScatter(nullptr),
+ m_mtl(),
+ m_camera(),
+ m_normalSize(0)
+{
+}
+
+HRESULT CSceneManjaladon::Init()
+{
+ HRESULT hr;
+ wchar_t strPath[MAX_PATH];
+ ID3D11Device * pDevice = DXUTGetD3D11Device();
+ ID3D11DeviceContext *pDeviceContext = DXUTGetD3D11DeviceContext();
+
+ // Load meshes
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"Manjaladon\\manjaladon.obj"));
+ V_RETURN(LoadObjMesh(strPath, pDevice, &m_meshManjaladon));
+
+ // Load textures
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"Manjaladon\\Manjaladon_d.bmp"));
+ V_RETURN(LoadTexture(strPath, pDevice, pDeviceContext, &m_pSrvDiffuse));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"Manjaladon\\Manjaladon_n.bmp"));
+ V_RETURN(LoadTexture(strPath, pDevice, pDeviceContext, &m_pSrvNormal, LT_Mipmap | LT_Linear));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"Manjaladon\\Manjaladon_s.bmp"));
+ V_RETURN(LoadTexture(strPath, pDevice, pDeviceContext, &m_pSrvSpec));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"Manjaladon\\Manjaladon_subsurface.bmp"));
+ V_RETURN(LoadTexture(strPath, pDevice, pDeviceContext, &m_pSrvDeepScatter));
+
+ // Set up materials
+
+ m_mtl.m_shader = SHADER_Skin;
+ m_mtl.m_aSrv[0] = m_pSrvDiffuse; m_mtl.m_textureSlots[0] = TEX_DIFFUSE0;
+ m_mtl.m_aSrv[1] = m_pSrvNormal; m_mtl.m_textureSlots[1] = TEX_NORMAL;
+ m_mtl.m_aSrv[2] = m_pSrvSpec; m_mtl.m_textureSlots[2] = TEX_SPEC;
+ m_mtl.m_aSrv[3] = m_pSrvDeepScatter; m_mtl.m_textureSlots[3] = TEX_DEEP_SCATTER_COLOR;
+ m_mtl.m_constants[0] = g_normalStrength;
+ m_mtl.m_constants[1] = g_glossSkin;
+
+ // Set up camera to orbit around the manjaladon
+
+ XMVECTOR posLookAt = XMLoadFloat3(&m_meshManjaladon.m_posCenter) + XMVectorSet(0.0f, 0.0f, 5.0f, 0.0f);
+ XMVECTOR posCamera = posLookAt + XMVectorSet(0.0f, 0.0f, 40.0f, 0.0f);
+ m_camera.SetViewParams(posCamera, posLookAt);
+
+ // Pull out normal map texture size for SSS mip level calculations
+
+ m_normalSize = GetTextureSize(m_pSrvNormal);
+
+ return S_OK;
+}
+
+void CSceneManjaladon::Release()
+{
+ m_meshManjaladon.Release();
+
+ SAFE_RELEASE(m_pSrvDiffuse);
+ SAFE_RELEASE(m_pSrvNormal);
+ SAFE_RELEASE(m_pSrvSpec);
+ SAFE_RELEASE(m_pSrvDeepScatter);
+}
+
+void CSceneManjaladon::GetBounds(XMFLOAT3 * pPosMin, XMFLOAT3 * pPosMax)
+{
+ assert(pPosMin);
+ assert(pPosMax);
+
+ *pPosMin = m_meshManjaladon.m_posMin;
+ *pPosMax = m_meshManjaladon.m_posMax;
+}
+
+void CSceneManjaladon::GetMeshesToDraw(std::vector<MeshToDraw> * pMeshesToDraw)
+{
+ assert(pMeshesToDraw);
+
+ // Allow updating normal strength and gloss in real-time
+ m_mtl.m_constants[0] = g_normalStrength;
+ m_mtl.m_constants[1] = g_glossSkin;
+
+ // Generate draw records
+
+ MeshToDraw aMtd[] =
+ {
+ { &m_mtl, &m_meshManjaladon, m_normalSize, m_meshManjaladon.m_uvScale, },
+ };
+ pMeshesToDraw->assign(&aMtd[0], &aMtd[dim(aMtd)]);
+}
+
+
+
+// CSceneWarriorHead implementation
+
+CSceneWarriorHead::CSceneWarriorHead()
+: m_meshHead(),
+ m_meshEyeL(),
+ m_meshEyeR(),
+ m_meshLashes(),
+ m_pSrvDiffuseHead(nullptr),
+ m_pSrvNormalHead(nullptr),
+ m_pSrvSpecHead(nullptr),
+ m_pSrvDeepScatterHead(nullptr),
+ m_pSrvDiffuseEyeSclera(nullptr),
+ m_pSrvNormalEyeSclera(nullptr),
+ m_pSrvDiffuseEyeIris(nullptr),
+ m_pSrvDiffuseLashes(nullptr),
+ m_mtlHead(),
+ m_mtlEye(),
+ m_mtlLashes(),
+ m_camera(),
+ m_normalHeadSize(0),
+ m_normalEyeSize(0)
+{
+}
+
+HRESULT CSceneWarriorHead::Init()
+{
+ HRESULT hr;
+ wchar_t strPath[MAX_PATH];
+ ID3D11Device * pDevice = DXUTGetD3D11Device();
+ ID3D11DeviceContext *pDeviceContext = DXUTGetD3D11DeviceContext();
+
+ // Load meshes
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"WarriorHead\\WarriorHead.obj"));
+ V_RETURN(LoadObjMesh(strPath, pDevice, &m_meshHead));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"WarriorHead\\EyeL.obj"));
+ V_RETURN(LoadObjMesh(strPath, pDevice, &m_meshEyeL));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"WarriorHead\\EyeR.obj"));
+ V_RETURN(LoadObjMesh(strPath, pDevice, &m_meshEyeR));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"WarriorHead\\Lashes.obj"));
+ V_RETURN(LoadObjMesh(strPath, pDevice, &m_meshLashes));
+
+ // Load textures
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"WarriorHead\\diffuse.bmp"));
+ V_RETURN(LoadTexture(strPath, pDevice, pDeviceContext, &m_pSrvDiffuseHead));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"WarriorHead\\normal.bmp"));
+ V_RETURN(LoadTexture(strPath, pDevice, pDeviceContext, &m_pSrvNormalHead, LT_Mipmap | LT_Linear));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"WarriorHead\\deepscatter.bmp"));
+ V_RETURN(LoadTexture(strPath, pDevice, pDeviceContext, &m_pSrvDeepScatterHead));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"WarriorHead\\eyeHazel.bmp"));
+ V_RETURN(LoadTexture(strPath, pDevice, pDeviceContext, &m_pSrvDiffuseEyeSclera));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"DigitalIra\\eyeballNormalMap.bmp"));
+ V_RETURN(LoadTexture(strPath, pDevice, pDeviceContext, &m_pSrvNormalEyeSclera, LT_Mipmap | LT_Linear));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"WarriorHead\\eyeHazel.bmp"));
+ V_RETURN(LoadTexture(strPath, pDevice, pDeviceContext, &m_pSrvDiffuseEyeIris));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), L"WarriorHead\\lashes.bmp"));
+ V_RETURN(LoadTexture(strPath, pDevice, pDeviceContext, &m_pSrvDiffuseLashes));
+
+ // Create 1x1 spec texture
+
+ m_pSrvSpecHead = Create1x1Texture(
+ g_specReflectanceSkinDefault,
+ g_specReflectanceSkinDefault,
+ g_specReflectanceSkinDefault,
+ true);
+
+ // Set up materials
+
+ m_mtlHead.m_shader = SHADER_Skin;
+ m_mtlHead.m_aSrv[0] = m_pSrvDiffuseHead; m_mtlHead.m_textureSlots[0] = TEX_DIFFUSE0;
+ m_mtlHead.m_aSrv[1] = m_pSrvNormalHead; m_mtlHead.m_textureSlots[1] = TEX_NORMAL;
+ m_mtlHead.m_aSrv[2] = m_pSrvSpecHead; m_mtlHead.m_textureSlots[2] = TEX_SPEC;
+ m_mtlHead.m_aSrv[3] = m_pSrvDeepScatterHead; m_mtlHead.m_textureSlots[3] = TEX_DEEP_SCATTER_COLOR;
+ m_mtlHead.m_constants[0] = g_normalStrength;
+ m_mtlHead.m_constants[1] = g_glossSkin;
+
+ m_mtlEye.m_shader = SHADER_Eye;
+ m_mtlEye.m_aSrv[0] = m_pSrvDiffuseEyeSclera; m_mtlEye.m_textureSlots[0] = TEX_DIFFUSE0;
+ m_mtlEye.m_aSrv[1] = m_pSrvDiffuseEyeIris; m_mtlEye.m_textureSlots[1] = TEX_DIFFUSE1;
+ m_mtlEye.m_aSrv[2] = m_pSrvNormalEyeSclera; m_mtlEye.m_textureSlots[2] = TEX_NORMAL;
+ m_mtlEye.m_constants[0] = 0.05f; // normal strength
+ m_mtlEye.m_constants[1] = g_specReflectanceEye;
+ m_mtlEye.m_constants[2] = g_glossEye;
+ m_mtlEye.m_constants[4] = g_rgbDeepScatterEye[0];
+ m_mtlEye.m_constants[5] = g_rgbDeepScatterEye[1];
+ m_mtlEye.m_constants[6] = g_rgbDeepScatterEye[2];
+ m_mtlEye.m_constants[7] = 0.200f; // Radius of iris in iris texture (in UV units)
+ m_mtlEye.m_constants[8] = 0.205f; // Radius of iris in schlera texture (in UV units)
+ m_mtlEye.m_constants[9] = 30.0f; // Controls hardness/softness of iris edge
+ m_mtlEye.m_constants[10] = 0.0f; // How much the iris is dilated
+
+ m_mtlLashes.m_shader = SHADER_Hair;
+ m_mtlLashes.m_aSrv[0] = m_pSrvDiffuseLashes; m_mtlLashes.m_textureSlots[0] = TEX_DIFFUSE0;
+ m_mtlLashes.m_constants[0] = g_specReflectanceHair;
+ m_mtlLashes.m_constants[1] = g_glossHair;
+
+ // Set up camera to orbit around the head
+
+ XMVECTOR posLookAt = XMLoadFloat3(&m_meshHead.m_posCenter);
+ XMVECTOR posCamera = posLookAt + XMVectorSet(0.0f, 0.0f, 60.0f, 0.0f);
+ m_camera.SetViewParams(posCamera, posLookAt);
+
+ // Pull out normal map texture sizes for SSS mip level calculations
+
+ m_normalHeadSize = GetTextureSize(m_pSrvNormalHead);
+ m_normalEyeSize = GetTextureSize(m_pSrvNormalEyeSclera);
+
+ return S_OK;
+}
+
+void CSceneWarriorHead::Release()
+{
+ m_meshHead.Release();
+ m_meshEyeL.Release();
+ m_meshEyeR.Release();
+ m_meshLashes.Release();
+
+ SAFE_RELEASE(m_pSrvDiffuseHead);
+ SAFE_RELEASE(m_pSrvNormalHead);
+ SAFE_RELEASE(m_pSrvSpecHead);
+ SAFE_RELEASE(m_pSrvDeepScatterHead);
+
+ SAFE_RELEASE(m_pSrvDiffuseEyeSclera);
+ SAFE_RELEASE(m_pSrvNormalEyeSclera);
+ SAFE_RELEASE(m_pSrvDiffuseEyeIris);
+
+ SAFE_RELEASE(m_pSrvDiffuseLashes);
+}
+
+void CSceneWarriorHead::GetBounds(XMFLOAT3 * pPosMin, XMFLOAT3 * pPosMax)
+{
+ assert(pPosMin);
+ assert(pPosMax);
+
+ *pPosMin = m_meshHead.m_posMin;
+ *pPosMax = m_meshHead.m_posMax;
+}
+
+void CSceneWarriorHead::GetMeshesToDraw(std::vector<MeshToDraw> * pMeshesToDraw)
+{
+ assert(pMeshesToDraw);
+
+ // Allow updating normal strength and gloss in real-time
+ m_mtlHead.m_constants[0] = g_normalStrength;
+ m_mtlHead.m_constants[1] = g_glossSkin;
+ m_mtlEye.m_constants[2] = g_glossEye;
+
+ m_mtlEye.m_constants[7] = g_irisRadiusSource;
+ m_mtlEye.m_constants[8] = g_irisRadiusDest;
+ m_mtlEye.m_constants[9] = g_irisEdgeHardness;
+ m_mtlEye.m_constants[10] = g_irisDilation;
+
+ m_mtlLashes.m_constants[0] = g_specReflectanceHair;
+ m_mtlLashes.m_constants[1] = g_glossHair;
+
+ // Generate draw records
+
+ MeshToDraw aMtd[] =
+ {
+ { &m_mtlHead, &m_meshHead, m_normalHeadSize, m_meshHead.m_uvScale, },
+ { &m_mtlEye, &m_meshEyeL, m_normalEyeSize, m_meshEyeL.m_uvScale, },
+ { &m_mtlEye, &m_meshEyeR, m_normalEyeSize, m_meshEyeR.m_uvScale, },
+ { &m_mtlLashes, &m_meshLashes, },
+ };
+
+ pMeshesToDraw->assign(&aMtd[0], &aMtd[dim(aMtd)]);
+}
+
+
+
+// CBackground implementation
+
+CBackground::CBackground()
+: m_pSrvCubeEnv(nullptr),
+ m_pSrvCubeDiff(nullptr),
+ m_pSrvCubeSpec(nullptr),
+ m_exposure(0.0f)
+{
+}
+
+HRESULT CBackground::Init(
+ const wchar_t * strCubeEnv,
+ const wchar_t * strCubeDiff,
+ const wchar_t * strCubeSpec,
+ float exposure /* = 1.0f */)
+{
+ HRESULT hr;
+ wchar_t strPath[MAX_PATH];
+ ID3D11Device * pDevice = DXUTGetD3D11Device();
+ ID3D11DeviceContext *pDeviceContext = DXUTGetD3D11DeviceContext();
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), strCubeEnv));
+ V_RETURN(LoadTexture(strPath, pDevice, &m_pSrvCubeEnv, LT_HDR | LT_Cubemap));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), strCubeDiff));
+ V_RETURN(LoadTexture(strPath, pDevice, &m_pSrvCubeDiff, LT_HDR | LT_Cubemap));
+
+ V_RETURN(DXUTFindDXSDKMediaFileCch(strPath, dim(strPath), strCubeSpec));
+ V_RETURN(LoadTexture(strPath, pDevice, pDeviceContext, &m_pSrvCubeSpec, LT_Mipmap | LT_HDR | LT_Cubemap));
+
+ m_exposure = exposure;
+
+ return S_OK;
+}
+
+void CBackground::Release()
+{
+ SAFE_RELEASE(m_pSrvCubeEnv);
+ SAFE_RELEASE(m_pSrvCubeDiff);
+ SAFE_RELEASE(m_pSrvCubeSpec);
+}
diff --git a/samples/d3d11/scenes.h b/samples/d3d11/scenes.h
new file mode 100644
index 0000000..0b8aa91
--- /dev/null
+++ b/samples/d3d11/scenes.h
@@ -0,0 +1,299 @@
+//----------------------------------------------------------------------------------
+// File: FaceWorks/samples/sample_d3d11/scenes.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.
+//
+//----------------------------------------------------------------------------------
+
+
+#pragma once
+
+#include "util.h"
+#include "shader.h"
+
+
+
+struct MeshToDraw
+{
+ Material * m_pMtl;
+ CMesh * m_pMesh;
+
+ // Parameters for SSS
+ int m_normalMapSize; // Pixel size of normal map
+ float m_averageUVScale; // Average UV scale of the mesh
+};
+
+class CScene
+{
+public:
+ virtual ~CScene() = 0;
+
+ virtual HRESULT Init() = 0;
+ virtual void Release() = 0;
+
+ virtual CBaseCamera * Camera() = 0;
+
+ virtual void GetBounds(DirectX::XMFLOAT3 * pPosMin, DirectX::XMFLOAT3 * pPosMax) = 0;
+ virtual void GetMeshesToDraw(std::vector<MeshToDraw> * pMeshesToDraw) = 0;
+};
+
+class CSceneDigitalIra : public CScene
+{
+public:
+ CSceneDigitalIra();
+
+ virtual HRESULT Init() override;
+ virtual void Release() override;
+
+ virtual CBaseCamera* Camera() override;
+
+ virtual void GetBounds(DirectX::XMFLOAT3 * pPosMin, DirectX::XMFLOAT3 * pPosMax) override;
+ virtual void GetMeshesToDraw(std::vector<MeshToDraw> * pMeshesToDraw) override;
+
+ CMesh m_meshHead;
+ CMesh m_meshEyeL;
+ CMesh m_meshEyeR;
+ CMesh m_meshLashes;
+ CMesh m_meshBrows;
+
+ ID3D11ShaderResourceView * m_pSrvDiffuseHead;
+ ID3D11ShaderResourceView * m_pSrvNormalHead;
+ ID3D11ShaderResourceView * m_pSrvSpecHead;
+ ID3D11ShaderResourceView * m_pSrvDeepScatterHead;
+
+ ID3D11ShaderResourceView * m_pSrvDiffuseEyeSclera;
+ ID3D11ShaderResourceView * m_pSrvNormalEyeSclera;
+ ID3D11ShaderResourceView * m_pSrvDiffuseEyeIris;
+
+ ID3D11ShaderResourceView * m_pSrvDiffuseLashes;
+ ID3D11ShaderResourceView * m_pSrvDiffuseBrows;
+
+ Material m_mtlHead;
+ Material m_mtlEye;
+ Material m_mtlLashes;
+ Material m_mtlBrows;
+
+ CMayaStyleCamera m_camera;
+
+ int m_normalHeadSize;
+ int m_normalEyeSize;
+};
+
+class CSceneTest : public CScene
+{
+public:
+ CSceneTest();
+
+ virtual HRESULT Init() override;
+ virtual void Release() override;
+
+ virtual CBaseCamera* Camera() override;
+
+ virtual void GetBounds(DirectX::XMFLOAT3 * pPosMin, DirectX::XMFLOAT3 * pPosMax) override;
+ virtual void GetMeshesToDraw(std::vector<MeshToDraw> * pMeshesToDraw) override;
+
+ CMesh m_meshPlanes;
+ CMesh m_meshShadower;
+ CMesh m_aMeshSpheres[7];
+
+ ID3D11ShaderResourceView * m_pSrvDiffuse;
+ ID3D11ShaderResourceView * m_pSrvNormalFlat;
+ ID3D11ShaderResourceView * m_pSrvSpec;
+ ID3D11ShaderResourceView * m_pSrvDeepScatter;
+
+ Material m_mtl;
+
+ CFirstPersonCameraRH m_camera;
+};
+
+class CSceneHand : public CScene
+{
+public:
+ CSceneHand();
+
+ virtual HRESULT Init() override;
+ virtual void Release() override;
+
+ virtual CBaseCamera* Camera() override;
+
+ virtual void GetBounds(DirectX::XMFLOAT3 * pPosMin, DirectX::XMFLOAT3 * pPosMax) override;
+ virtual void GetMeshesToDraw(std::vector<MeshToDraw> * pMeshesToDraw) override;
+
+ CMesh m_meshHand;
+
+ ID3D11ShaderResourceView * m_pSrvDiffuse;
+ ID3D11ShaderResourceView * m_pSrvNormalFlat;
+ ID3D11ShaderResourceView * m_pSrvSpec;
+ ID3D11ShaderResourceView * m_pSrvDeepScatter;
+
+ Material m_mtl;
+
+ CMayaStyleCamera m_camera;
+};
+
+class CSceneDragon : public CScene
+{
+public:
+ CSceneDragon();
+
+ virtual HRESULT Init();
+ virtual void Release();
+
+ virtual CBaseCamera * Camera() { return &m_camera; }
+
+ virtual void GetBounds(DirectX::XMFLOAT3 * pPosMin, DirectX::XMFLOAT3 * pPosMax);
+ virtual void GetMeshesToDraw(std::vector<MeshToDraw> * pMeshesToDraw);
+
+ CMesh m_meshDragon;
+
+ ID3D11ShaderResourceView * m_pSrvDiffuse;
+ ID3D11ShaderResourceView * m_pSrvNormal;
+ ID3D11ShaderResourceView * m_pSrvSpec;
+ ID3D11ShaderResourceView * m_pSrvDeepScatter;
+
+ Material m_mtl;
+
+ CMayaStyleCamera m_camera;
+
+ int m_normalSize;
+};
+
+class CSceneLPSHead : public CScene
+{
+public:
+ CSceneLPSHead();
+
+ virtual HRESULT Init();
+ virtual void Release();
+
+ virtual CBaseCamera * Camera() { return &m_camera; }
+
+ virtual void GetBounds(DirectX::XMFLOAT3 * pPosMin, DirectX::XMFLOAT3 * pPosMax);
+ virtual void GetMeshesToDraw(std::vector<MeshToDraw> * pMeshesToDraw);
+
+ CMesh m_meshHead;
+
+ ID3D11ShaderResourceView * m_pSrvDiffuseHead;
+ ID3D11ShaderResourceView * m_pSrvNormalHead;
+ ID3D11ShaderResourceView * m_pSrvSpecHead;
+ ID3D11ShaderResourceView * m_pSrvDeepScatterHead;
+
+ Material m_mtlHead;
+
+ CMayaStyleCamera m_camera;
+
+ int m_normalHeadSize;
+};
+
+class CSceneManjaladon : public CScene
+{
+public:
+ CSceneManjaladon();
+
+ virtual HRESULT Init();
+ virtual void Release();
+
+ virtual CBaseCamera * Camera() { return &m_camera; }
+
+ virtual void GetBounds(DirectX::XMFLOAT3 * pPosMin, DirectX::XMFLOAT3 * pPosMax);
+ virtual void GetMeshesToDraw(std::vector<MeshToDraw> * pMeshesToDraw);
+
+ CMesh m_meshManjaladon;
+
+ ID3D11ShaderResourceView * m_pSrvDiffuse;
+ ID3D11ShaderResourceView * m_pSrvNormal;
+ ID3D11ShaderResourceView * m_pSrvSpec;
+ ID3D11ShaderResourceView * m_pSrvDeepScatter;
+
+ Material m_mtl;
+
+ CMayaStyleCamera m_camera;
+
+ int m_normalSize;
+};
+
+class CSceneWarriorHead : public CScene
+{
+public:
+ CSceneWarriorHead();
+
+ virtual HRESULT Init();
+ virtual void Release();
+
+ virtual CBaseCamera * Camera() { return &m_camera; }
+
+ virtual void GetBounds(DirectX::XMFLOAT3 * pPosMin, DirectX::XMFLOAT3 * pPosMax);
+ virtual void GetMeshesToDraw(std::vector<MeshToDraw> * pMeshesToDraw);
+
+ CMesh m_meshHead;
+ CMesh m_meshEyeL;
+ CMesh m_meshEyeR;
+ CMesh m_meshLashes;
+
+ ID3D11ShaderResourceView * m_pSrvDiffuseHead;
+ ID3D11ShaderResourceView * m_pSrvNormalHead;
+ ID3D11ShaderResourceView * m_pSrvSpecHead;
+ ID3D11ShaderResourceView * m_pSrvDeepScatterHead;
+
+ ID3D11ShaderResourceView * m_pSrvDiffuseEyeSclera;
+ ID3D11ShaderResourceView * m_pSrvNormalEyeSclera;
+ ID3D11ShaderResourceView * m_pSrvDiffuseEyeIris;
+
+ ID3D11ShaderResourceView * m_pSrvDiffuseLashes;
+
+ Material m_mtlHead;
+ Material m_mtlEye;
+ Material m_mtlLashes;
+
+ CMayaStyleCamera m_camera;
+
+ int m_normalHeadSize;
+ int m_normalEyeSize;
+};
+
+
+
+class CBackground
+{
+public:
+ CBackground();
+
+ HRESULT Init(
+ const wchar_t * strCubeEnv,
+ const wchar_t * strCubeDiff,
+ const wchar_t * strCubeSpec,
+ float exposure = 1.0f);
+ void Release();
+
+ ID3D11ShaderResourceView * m_pSrvCubeEnv;
+ ID3D11ShaderResourceView * m_pSrvCubeDiff;
+ ID3D11ShaderResourceView * m_pSrvCubeSpec;
+ float m_exposure;
+};
diff --git a/samples/d3d11/shader.cpp b/samples/d3d11/shader.cpp
new file mode 100644
index 0000000..8ef262f
--- /dev/null
+++ b/samples/d3d11/shader.cpp
@@ -0,0 +1,861 @@
+//----------------------------------------------------------------------------------
+// File: FaceWorks/samples/sample_d3d11/shader.cpp
+// 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.
+//
+//----------------------------------------------------------------------------------
+
+
+#include "shader.h"
+#include "util.h"
+#include "shaders/resources.h"
+
+#include <GFSDK_FaceWorks.h>
+
+// These headers are generated by the build process, and contain precompiled bytecode
+// for all of the fixed shaders (not generated dynamically using feature flags)
+#include "copy_ps.h"
+#include "create_vsm_ps.h"
+#include "curvature_vs.h"
+#include "curvature_ps.h"
+#include "gaussian_ps.h"
+#include "hair_ps.h"
+#include "screen_vs.h"
+#include "shadow_vs.h"
+#include "skybox_vs.h"
+#include "skybox_ps.h"
+#include "tess_vs.h"
+#include "tess_hs.h"
+#include "tess_ds.h"
+#include "thickness_ps.h"
+#include "world_vs.h"
+
+
+
+// Constant buffer size must be a multiple of 16 bytes
+inline unsigned int align16(unsigned int size)
+{
+ return ((size + 15) / 16) * 16;
+}
+
+
+
+// CShaderManager implementation
+
+CShaderManager g_shdmgr;
+
+CShaderManager::CShaderManager()
+: m_pPsCopy(nullptr),
+ m_pPsCreateVSM(nullptr),
+ m_pVsCurvature(nullptr),
+ m_pPsCurvature(nullptr),
+ m_pPsThickness(nullptr),
+ m_pPsGaussian(nullptr),
+ m_pPsHair(nullptr),
+ m_pVsScreen(nullptr),
+ m_pVsShadow(nullptr),
+ m_pVsSkybox(nullptr),
+ m_pPsSkybox(nullptr),
+ m_pVsTess(nullptr),
+ m_pHsTess(nullptr),
+ m_pDsTess(nullptr),
+ m_pVsWorld(nullptr),
+ m_pSsPointClamp(nullptr),
+ m_pSsBilinearClamp(nullptr),
+ m_pSsTrilinearRepeat(nullptr),
+ m_pSsTrilinearRepeatAniso(nullptr),
+ m_pSsPCF(nullptr),
+ m_pInputLayout(nullptr),
+ m_pCbufDebug(nullptr),
+ m_pCbufFrame(nullptr),
+ m_pCbufShader(nullptr),
+ m_mapSkinFeaturesToShader(),
+ m_mapEyeFeaturesToShader()
+{
+}
+
+HRESULT CShaderManager::Init(ID3D11Device * pDevice)
+{
+ HRESULT hr;
+
+ // Initialize all the fixed shaders from bytecode
+ V_RETURN(pDevice->CreatePixelShader(copy_ps_bytecode, dim(copy_ps_bytecode), nullptr, &m_pPsCopy));
+ V_RETURN(pDevice->CreatePixelShader(create_vsm_ps_bytecode, dim(create_vsm_ps_bytecode), nullptr, &m_pPsCreateVSM));
+ V_RETURN(pDevice->CreateVertexShader(curvature_vs_bytecode, dim(curvature_vs_bytecode), nullptr, &m_pVsCurvature));
+ V_RETURN(pDevice->CreatePixelShader(curvature_ps_bytecode, dim(curvature_ps_bytecode), nullptr, &m_pPsCurvature));
+ V_RETURN(pDevice->CreatePixelShader(gaussian_ps_bytecode, dim(gaussian_ps_bytecode), nullptr, &m_pPsGaussian));
+ V_RETURN(pDevice->CreatePixelShader(hair_ps_bytecode, dim(hair_ps_bytecode), nullptr, &m_pPsHair));
+ V_RETURN(pDevice->CreateVertexShader(screen_vs_bytecode, dim(screen_vs_bytecode), nullptr, &m_pVsScreen));
+ V_RETURN(pDevice->CreateVertexShader(shadow_vs_bytecode, dim(shadow_vs_bytecode), nullptr, &m_pVsShadow));
+ V_RETURN(pDevice->CreateVertexShader(skybox_vs_bytecode, dim(skybox_vs_bytecode), nullptr, &m_pVsSkybox));
+ V_RETURN(pDevice->CreatePixelShader(skybox_ps_bytecode, dim(skybox_ps_bytecode), nullptr, &m_pPsSkybox));
+ V_RETURN(pDevice->CreateVertexShader(tess_vs_bytecode, dim(tess_vs_bytecode), nullptr, &m_pVsTess));
+ V_RETURN(pDevice->CreateHullShader(tess_hs_bytecode, dim(tess_hs_bytecode), nullptr, &m_pHsTess));
+ V_RETURN(pDevice->CreateDomainShader(tess_ds_bytecode, dim(tess_ds_bytecode), nullptr, &m_pDsTess));
+ V_RETURN(pDevice->CreatePixelShader(thickness_ps_bytecode, dim(thickness_ps_bytecode), nullptr, &m_pPsThickness));
+ V_RETURN(pDevice->CreateVertexShader(world_vs_bytecode, dim(world_vs_bytecode), nullptr, &m_pVsWorld));
+
+ // Initialize the sampler states
+
+ D3D11_SAMPLER_DESC sampDesc =
+ {
+ D3D11_FILTER_MIN_MAG_MIP_POINT,
+ D3D11_TEXTURE_ADDRESS_CLAMP,
+ D3D11_TEXTURE_ADDRESS_CLAMP,
+ D3D11_TEXTURE_ADDRESS_CLAMP,
+ 0.0f,
+ 1,
+ D3D11_COMPARISON_FUNC(0),
+ { 0.0f, 0.0f, 0.0f, 0.0f },
+ 0.0f,
+ FLT_MAX,
+ };
+ V_RETURN(pDevice->CreateSamplerState(&sampDesc, &m_pSsPointClamp));
+
+ sampDesc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
+ V_RETURN(pDevice->CreateSamplerState(&sampDesc, &m_pSsBilinearClamp));
+
+ 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;
+ V_RETURN(pDevice->CreateSamplerState(&sampDesc, &m_pSsTrilinearRepeat));
+
+ sampDesc.Filter = D3D11_FILTER_ANISOTROPIC;
+ sampDesc.MaxAnisotropy = 16;
+ V_RETURN(pDevice->CreateSamplerState(&sampDesc, &m_pSsTrilinearRepeatAniso));
+
+ sampDesc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT;
+ sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_BORDER;
+ sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_BORDER;
+ sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_BORDER;
+ sampDesc.MaxAnisotropy = 1;
+ sampDesc.ComparisonFunc = D3D11_COMPARISON_LESS_EQUAL;
+ sampDesc.BorderColor[0] = 1.0f;
+ sampDesc.BorderColor[1] = 1.0f;
+ sampDesc.BorderColor[2] = 1.0f;
+ sampDesc.BorderColor[3] = 1.0f;
+ V_RETURN(pDevice->CreateSamplerState(&sampDesc, &m_pSsPCF));
+
+ // Initialize the input layout, and validate it against all the vertex shaders
+
+ D3D11_INPUT_ELEMENT_DESC aInputDescs[] =
+ {
+ { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, UINT(offsetof(Vertex, m_pos)), D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, UINT(offsetof(Vertex, m_normal)), D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ { "UV", 0, DXGI_FORMAT_R32G32_FLOAT, 0, UINT(offsetof(Vertex, m_uv)), D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ { "TANGENT", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, UINT(offsetof(Vertex, m_tangent)), D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ { "CURVATURE", 0, DXGI_FORMAT_R32_FLOAT, 0, UINT(offsetof(Vertex, m_curvature)), D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ };
+
+ V_RETURN(pDevice->CreateInputLayout(
+ aInputDescs, dim(aInputDescs),
+ curvature_vs_bytecode, dim(curvature_vs_bytecode),
+ &m_pInputLayout));
+
+ // Note: calling CreateInputLayout with nullptr for the 5th parameter will crash
+ // the VS2012 graphics debugger. Turn on this define if you need to graphics-debug.
+ // Bug filed with MS at https://connect.microsoft.com/VisualStudio/feedback/details/790030/
+ // Supposed to be fixed in VS2013.
+#define VS_GRAPHICS_DEBUG 0
+#if !VS_GRAPHICS_DEBUG
+ V_RETURN(pDevice->CreateInputLayout(
+ aInputDescs, dim(aInputDescs),
+ screen_vs_bytecode, dim(screen_vs_bytecode),
+ nullptr));
+ V_RETURN(pDevice->CreateInputLayout(
+ aInputDescs, dim(aInputDescs),
+ shadow_vs_bytecode, dim(shadow_vs_bytecode),
+ nullptr));
+ V_RETURN(pDevice->CreateInputLayout(
+ aInputDescs, dim(aInputDescs),
+ skybox_vs_bytecode, dim(skybox_vs_bytecode),
+ nullptr));
+ V_RETURN(pDevice->CreateInputLayout(
+ aInputDescs, dim(aInputDescs),
+ tess_vs_bytecode, dim(tess_vs_bytecode),
+ nullptr));
+ V_RETURN(pDevice->CreateInputLayout(
+ aInputDescs, dim(aInputDescs),
+ world_vs_bytecode, dim(world_vs_bytecode),
+ nullptr));
+#endif // !VS_GRAPHICS_DEBUG
+
+ // Initialize the constant buffers
+
+ D3D11_BUFFER_DESC bufDesc =
+ {
+ align16(sizeof(CbufDebug)),
+ D3D11_USAGE_DYNAMIC,
+ D3D11_BIND_CONSTANT_BUFFER,
+ D3D11_CPU_ACCESS_WRITE,
+ };
+
+ V_RETURN(pDevice->CreateBuffer(&bufDesc, nullptr, &m_pCbufDebug));
+
+ bufDesc.ByteWidth = align16(sizeof(CbufFrame));
+ V_RETURN(pDevice->CreateBuffer(&bufDesc, nullptr, &m_pCbufFrame));
+
+ bufDesc.ByteWidth = align16(sizeof_field(Material, m_constants));
+ V_RETURN(pDevice->CreateBuffer(&bufDesc, nullptr, &m_pCbufShader));
+
+ return S_OK;
+}
+
+void CShaderManager::InitFrame(
+ ID3D11DeviceContext * pCtx,
+ const CbufDebug * pCbufDebug,
+ const CbufFrame * pCbufFrame,
+ ID3D11ShaderResourceView * pSrvCubeDiffuse,
+ ID3D11ShaderResourceView * pSrvCubeSpec,
+ ID3D11ShaderResourceView * pSrvCurvatureLUT,
+ ID3D11ShaderResourceView * pSrvShadowLUT)
+{
+ HRESULT hr;
+
+ // Set all the samplers
+ pCtx->PSSetSamplers(SAMP_POINT_CLAMP, 1, &m_pSsPointClamp);
+ pCtx->PSSetSamplers(SAMP_BILINEAR_CLAMP, 1, &m_pSsBilinearClamp);
+ pCtx->PSSetSamplers(SAMP_TRILINEAR_REPEAT, 1, &m_pSsTrilinearRepeat);
+ pCtx->PSSetSamplers(SAMP_TRILINEAR_REPEAT_ANISO, 1, &m_pSsTrilinearRepeatAniso);
+ pCtx->PSSetSamplers(SAMP_PCF, 1, &m_pSsPCF);
+
+ // Set the input assembler state
+ pCtx->IASetInputLayout(m_pInputLayout);
+ pCtx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+
+ // Update the constant buffers
+
+ D3D11_MAPPED_SUBRESOURCE map = {};
+ V(pCtx->Map(m_pCbufDebug, 0, D3D11_MAP_WRITE_DISCARD, 0, &map));
+ memcpy(map.pData, pCbufDebug, sizeof(CbufDebug));
+ pCtx->Unmap(m_pCbufDebug, 0);
+
+ V(pCtx->Map(m_pCbufFrame, 0, D3D11_MAP_WRITE_DISCARD, 0, &map));
+ memcpy(map.pData, pCbufFrame, sizeof(CbufFrame));
+ pCtx->Unmap(m_pCbufFrame, 0);
+
+ // Set the constant buffers to all shader stages
+ pCtx->VSSetConstantBuffers(CB_DEBUG, 1, &m_pCbufDebug);
+ pCtx->HSSetConstantBuffers(CB_DEBUG, 1, &m_pCbufDebug);
+ pCtx->DSSetConstantBuffers(CB_DEBUG, 1, &m_pCbufDebug);
+ pCtx->PSSetConstantBuffers(CB_DEBUG, 1, &m_pCbufDebug);
+ pCtx->VSSetConstantBuffers(CB_FRAME, 1, &m_pCbufFrame);
+ pCtx->HSSetConstantBuffers(CB_FRAME, 1, &m_pCbufFrame);
+ pCtx->DSSetConstantBuffers(CB_FRAME, 1, &m_pCbufFrame);
+ pCtx->PSSetConstantBuffers(CB_FRAME, 1, &m_pCbufFrame);
+ pCtx->VSSetConstantBuffers(CB_SHADER, 1, &m_pCbufShader);
+ pCtx->HSSetConstantBuffers(CB_SHADER, 1, &m_pCbufShader);
+ pCtx->DSSetConstantBuffers(CB_SHADER, 1, &m_pCbufShader);
+ pCtx->PSSetConstantBuffers(CB_SHADER, 1, &m_pCbufShader);
+
+ // Set the textures that are kept for the whole frame
+ pCtx->PSSetShaderResources(TEX_CUBE_DIFFUSE, 1, &pSrvCubeDiffuse);
+ pCtx->PSSetShaderResources(TEX_CUBE_SPEC, 1, &pSrvCubeSpec);
+ pCtx->PSSetShaderResources(TEX_CURVATURE_LUT, 1, &pSrvCurvatureLUT);
+ pCtx->PSSetShaderResources(TEX_SHADOW_LUT, 1, &pSrvShadowLUT);
+}
+
+void CShaderManager::BindShadowTextures(
+ ID3D11DeviceContext * pCtx,
+ ID3D11ShaderResourceView * pSrvShadowMap,
+ ID3D11ShaderResourceView * pSrvVSM)
+{
+ pCtx->PSSetShaderResources(TEX_SHADOW_MAP, 1, &pSrvShadowMap);
+ pCtx->PSSetShaderResources(TEX_VSM, 1, &pSrvVSM);
+}
+
+
+
+// Include helper class for D3DCompile API
+struct IncludeHelper : public ID3DInclude
+{
+ virtual ~IncludeHelper()
+ {
+ }
+
+ std::wstring m_dirsToTry[2];
+ std::vector<std::vector<char> > m_openFiles;
+
+ IncludeHelper()
+ {
+ // Get the path to the .exe is located
+ HMODULE hModule = GetModuleHandleW(nullptr);
+ wchar_t path[MAX_PATH];
+ GetModuleFileNameW(hModule, path, MAX_PATH);
+
+ // Trim off the .exe filename, leaving just the directory
+ wchar_t * pBasename = wcsrchr(path, L'\\');
+ if (pBasename)
+ ++pBasename;
+ else
+ pBasename = path;
+ *pBasename = 0;
+
+ // Assemble paths to try for includes, relative to the .exe directory
+ m_dirsToTry[0] = path;
+ m_dirsToTry[0] += L"..\\..\\d3d11\\shaders\\";
+ m_dirsToTry[1] = path;
+ m_dirsToTry[1] += L"..\\..\\..\\include\\";
+ }
+
+ virtual HRESULT __stdcall Open(
+ D3D_INCLUDE_TYPE /*IncludeType*/,
+ LPCSTR pFileName,
+ LPCVOID /*pParentData*/,
+ LPCVOID * ppDataOut,
+ UINT * pBytesOut) override
+ {
+ assert(pFileName);
+ assert(ppDataOut);
+ assert(pBytesOut);
+
+ m_openFiles.push_back(std::vector<char>());
+
+ // Try to find the include in each possible directory
+ for (int i = 0; i < dim(m_dirsToTry); ++i)
+ {
+ wchar_t path[MAX_PATH];
+ swprintf_s(path, L"%s%hs", m_dirsToTry[i].c_str(), pFileName);
+ if (SUCCEEDED(LoadFile(path, &m_openFiles.back())))
+ {
+ *ppDataOut = &m_openFiles.back()[0];
+ *pBytesOut = UINT(m_openFiles.back().size());
+ DebugPrintf(L"Loaded include file: %hs\n", pFileName);
+ return S_OK;
+ }
+ }
+
+ m_openFiles.pop_back();
+
+ return E_FAIL;
+ }
+
+ virtual HRESULT __stdcall Close(LPCVOID pData) override
+ {
+ assert(pData);
+
+ for (int i = 0, n = int(m_openFiles.size()); i < n; ++i)
+ {
+ if (!m_openFiles[i].empty() &&
+ pData == &m_openFiles[i][0])
+ {
+ m_openFiles[i].clear();
+ return S_OK;
+ }
+ }
+
+ assert(false);
+ return E_FAIL;
+ }
+};
+
+bool CShaderManager::CompileShader(
+ ID3D11Device * pDevice,
+ const char * source,
+ ID3D11PixelShader ** ppPsOut)
+{
+ // Compile the source
+
+ UINT flags = 0;
+#if defined(_DEBUG)
+ flags |= D3DCOMPILE_SKIP_OPTIMIZATION | D3DCOMPILE_DEBUG | D3DCOMPILE_PREFER_FLOW_CONTROL;
+#endif
+
+ ID3DBlob * pBlobCode = nullptr;
+ ID3DBlob * pBlobErrors = nullptr;
+
+ IncludeHelper includeHelper;
+ HRESULT hr = D3DCompile(
+ source, strlen(source), "generated_ps",
+ nullptr, &includeHelper,
+ "main", "ps_5_0",
+ flags, 0,
+ &pBlobCode, &pBlobErrors);
+ if (pBlobErrors)
+ {
+ MessageBoxA(
+ DXUTGetHWND(),
+ static_cast<char *>(pBlobErrors->GetBufferPointer()),
+ "Shader Compile Error", MB_OK);
+ if (pBlobCode)
+ pBlobCode->Release();
+ pBlobErrors->Release();
+ return false;
+ }
+ if (FAILED(hr) || !pBlobCode)
+ {
+ MessageBox(
+ DXUTGetHWND(),
+ L"Shader failed to compile, but no error messages were generated.",
+ L"Shader Compile Error", MB_OK);
+ if (pBlobCode)
+ pBlobCode->Release();
+ return false;
+ }
+
+ // Create the shader on the device
+ if (FAILED(pDevice->CreatePixelShader(
+ pBlobCode->GetBufferPointer(), pBlobCode->GetBufferSize(),
+ nullptr, ppPsOut)))
+ {
+ MessageBox(
+ DXUTGetHWND(),
+ L"Couldn't create pixel shader on device.",
+ L"Shader Compile Error", MB_OK);
+ pBlobCode->Release();
+ return false;
+ }
+
+ pBlobCode->Release();
+ return true;
+}
+
+void CShaderManager::CreateSkinShader(ID3D11Device * pDevice, SHDFEATURES features)
+{
+ DebugPrintf(L"Generating skin shader with feature mask %d\n", features);
+
+ assert((features & SHDFEAT_PSMask) == features);
+
+ // Create source code for the shader
+ char source[512];
+ sprintf_s(
+ source,
+ "#include \"skin.hlsli\"\n"
+ "void main(\n"
+ " in Vertex i_vtx,\n"
+ " in float3 i_vecCamera : CAMERA,\n"
+ " in float4 i_uvzwShadow : UVZW_SHADOW,\n"
+ " out float3 o_rgbLit : SV_Target)\n"
+ "{\n"
+ " SkinMegashader(i_vtx, i_vecCamera, i_uvzwShadow, o_rgbLit, %s, %s);\n"
+ "}\n",
+ (features & SHDFEAT_SSS) ? "true" : "false",
+ (features & SHDFEAT_DeepScatter) ? "true" : "false"
+ );
+
+ // Compile it
+ ID3D11PixelShader * pPs = nullptr;
+ if (!CompileShader(pDevice, source, &pPs))
+ return;
+
+ // Store it in the map for future reference
+ assert(pPs);
+ m_mapSkinFeaturesToShader[features] = pPs;
+}
+
+void CShaderManager::CreateEyeShader(ID3D11Device * pDevice, SHDFEATURES features)
+{
+ DebugPrintf(L"Generating eye shader with feature mask %d\n", features);
+
+ assert((features & SHDFEAT_PSMask) == features);
+
+ // Create source code for the shader
+ char source[512];
+ sprintf_s(
+ source,
+ "#include \"eye.hlsli\"\n"
+ "void main(\n"
+ " in Vertex i_vtx,\n"
+ " in float3 i_vecCamera : CAMERA,\n"
+ " in float4 i_uvzwShadow : UVZW_SHADOW,\n"
+ " out float3 o_rgbLit : SV_Target)\n"
+ "{\n"
+ " EyeMegashader(i_vtx, i_vecCamera, i_uvzwShadow, o_rgbLit, %s, %s);\n"
+ "}\n",
+ (features & SHDFEAT_SSS) ? "true" : "false",
+ (features & SHDFEAT_DeepScatter) ? "true" : "false"
+ );
+
+ // Compile it
+ ID3D11PixelShader * pPs = nullptr;
+ if (!CompileShader(pDevice, source, &pPs))
+ return;
+
+ // Store it in the map for future reference
+ assert(pPs);
+ m_mapEyeFeaturesToShader[features] = pPs;
+}
+
+ID3D11PixelShader * CShaderManager::GetSkinShader(ID3D11Device * pDevice, SHDFEATURES features)
+{
+ features &= SHDFEAT_PSMask;
+
+ std::unordered_map<SHDFEATURES, ID3D11PixelShader *>::iterator i =
+ m_mapSkinFeaturesToShader.find(features);
+
+ if (i != m_mapSkinFeaturesToShader.end())
+ {
+ return i->second;
+ }
+
+ CreateSkinShader(pDevice, features);
+ return m_mapSkinFeaturesToShader[features];
+}
+
+ID3D11PixelShader * CShaderManager::GetEyeShader(ID3D11Device * pDevice, SHDFEATURES features)
+{
+ features &= SHDFEAT_PSMask;
+
+ std::unordered_map<SHDFEATURES, ID3D11PixelShader *>::iterator i =
+ m_mapEyeFeaturesToShader.find(features);
+
+ if (i != m_mapEyeFeaturesToShader.end())
+ {
+ return i->second;
+ }
+
+ CreateEyeShader(pDevice, features);
+ return m_mapEyeFeaturesToShader[features];
+}
+
+
+
+void CShaderManager::BindCopy(
+ ID3D11DeviceContext * pCtx,
+ ID3D11ShaderResourceView * pSrvSrc,
+ const DirectX::XMFLOAT4X4 & matTransformColor)
+{
+ pCtx->VSSetShader(m_pVsScreen, nullptr, 0);
+ pCtx->PSSetShader(m_pPsCopy, nullptr, 0);
+ pCtx->PSSetShaderResources(TEX_SOURCE, 1, &pSrvSrc);
+
+ // Update constant buffer
+ HRESULT hr;
+ D3D11_MAPPED_SUBRESOURCE map = {};
+ V(pCtx->Map(m_pCbufShader, 0, D3D11_MAP_WRITE_DISCARD, 0, &map));
+ memcpy(map.pData, &matTransformColor, sizeof(matTransformColor));
+ pCtx->Unmap(m_pCbufShader, 0);
+}
+
+void CShaderManager::BindCreateVSM(
+ ID3D11DeviceContext * pCtx,
+ ID3D11ShaderResourceView * pSrvSrc)
+{
+ pCtx->VSSetShader(m_pVsScreen, nullptr, 0);
+ pCtx->PSSetShader(m_pPsCreateVSM, nullptr, 0);
+ pCtx->PSSetShaderResources(TEX_SOURCE, 1, &pSrvSrc);
+}
+
+void CShaderManager::BindCurvature(
+ ID3D11DeviceContext * pCtx,
+ float curvatureScale,
+ float curvatureBias)
+{
+ pCtx->VSSetShader(m_pVsCurvature, nullptr, 0);
+ pCtx->PSSetShader(m_pPsCurvature, nullptr, 0);
+
+ // Update constant buffer
+ HRESULT hr;
+ D3D11_MAPPED_SUBRESOURCE map = {};
+ V(pCtx->Map(m_pCbufShader, 0, D3D11_MAP_WRITE_DISCARD, 0, &map));
+ static_cast<float *>(map.pData)[0] = curvatureScale;
+ static_cast<float *>(map.pData)[1] = curvatureBias;
+ pCtx->Unmap(m_pCbufShader, 0);
+}
+
+void CShaderManager::BindThickness(
+ ID3D11DeviceContext * pCtx,
+ GFSDK_FaceWorks_CBData * pFaceWorksCBData)
+{
+ pCtx->VSSetShader(m_pVsWorld, nullptr, 0);
+ pCtx->PSSetShader(m_pPsThickness, nullptr, 0);
+
+ // Update constant buffer
+ HRESULT hr;
+ D3D11_MAPPED_SUBRESOURCE map = {};
+ V(pCtx->Map(m_pCbufShader, 0, D3D11_MAP_WRITE_DISCARD, 0, &map));
+ memcpy(map.pData, pFaceWorksCBData, sizeof(GFSDK_FaceWorks_CBData));
+ pCtx->Unmap(m_pCbufShader, 0);
+}
+
+void CShaderManager::BindGaussian(
+ ID3D11DeviceContext * pCtx,
+ ID3D11ShaderResourceView * pSrvSrc,
+ float blurX,
+ float blurY)
+{
+ pCtx->VSSetShader(m_pVsScreen, nullptr, 0);
+ pCtx->PSSetShader(m_pPsGaussian, nullptr, 0);
+ pCtx->PSSetShaderResources(TEX_SOURCE, 1, &pSrvSrc);
+
+ // Update constant buffer
+ HRESULT hr;
+ D3D11_MAPPED_SUBRESOURCE map = {};
+ V(pCtx->Map(m_pCbufShader, 0, D3D11_MAP_WRITE_DISCARD, 0, &map));
+ static_cast<float *>(map.pData)[0] = blurX;
+ static_cast<float *>(map.pData)[1] = blurY;
+ pCtx->Unmap(m_pCbufShader, 0);
+}
+
+void CShaderManager::BindShadow(
+ ID3D11DeviceContext * pCtx,
+ const DirectX::XMFLOAT4X4 & matWorldToClipShadow)
+{
+ pCtx->VSSetShader(m_pVsShadow, nullptr, 0);
+ pCtx->PSSetShader(nullptr, nullptr, 0);
+
+ // Update constant buffer
+ HRESULT hr;
+ D3D11_MAPPED_SUBRESOURCE map = {};
+ V(pCtx->Map(m_pCbufShader, 0, D3D11_MAP_WRITE_DISCARD, 0, &map));
+ memcpy(map.pData, &matWorldToClipShadow, sizeof(matWorldToClipShadow));
+ pCtx->Unmap(m_pCbufShader, 0);
+}
+
+void CShaderManager::BindSkybox(
+ ID3D11DeviceContext * pCtx,
+ ID3D11ShaderResourceView * pSrvSkybox,
+ const DirectX::XMFLOAT4X4 & matClipToWorldAxes)
+{
+ pCtx->VSSetShader(m_pVsSkybox, nullptr, 0);
+ pCtx->PSSetShader(m_pPsSkybox, nullptr, 0);
+ pCtx->PSSetShaderResources(TEX_SOURCE, 1, &pSrvSkybox);
+
+ // Update constant buffer
+ HRESULT hr;
+ D3D11_MAPPED_SUBRESOURCE map = {};
+ V(pCtx->Map(m_pCbufShader, 0, D3D11_MAP_WRITE_DISCARD, 0, &map));
+ memcpy(map.pData, &matClipToWorldAxes, sizeof(matClipToWorldAxes));
+ pCtx->Unmap(m_pCbufShader, 0);
+}
+
+void CShaderManager::BindMaterial(
+ ID3D11DeviceContext * pCtx,
+ SHDFEATURES features,
+ const Material * pMtl)
+{
+ ID3D11Device * pDevice;
+ pCtx->GetDevice(&pDevice);
+
+ // Determine which pixel shader to use
+ ID3D11PixelShader * pPs;
+ switch (pMtl->m_shader)
+ {
+ case SHADER_Skin: pPs = GetSkinShader(pDevice, features); break;
+ case SHADER_Eye: pPs = GetEyeShader(pDevice, features); break;
+ case SHADER_Hair: pPs = m_pPsHair; break;
+ default:
+ assert(false);
+ return;
+ }
+
+ pDevice->Release();
+ assert(pPs);
+
+ pCtx->PSSetShader(pPs, nullptr, 0);
+
+ // Determine which vertex/tess shaders to use
+ if (features & SHDFEAT_Tessellation)
+ {
+ pCtx->VSSetShader(m_pVsTess, nullptr, 0);
+ pCtx->HSSetShader(m_pHsTess, nullptr, 0);
+ pCtx->DSSetShader(m_pDsTess, nullptr, 0);
+ pCtx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST);
+ }
+ else
+ {
+ pCtx->VSSetShader(m_pVsWorld, nullptr, 0);
+ }
+
+ // Bind textures
+ for (int i = 0; i < dim(pMtl->m_aSrv); ++i)
+ {
+ if (pMtl->m_aSrv[i])
+ pCtx->PSSetShaderResources(pMtl->m_textureSlots[i], 1, &pMtl->m_aSrv[i]);
+ }
+
+ // Update constant buffer
+ HRESULT hr;
+ D3D11_MAPPED_SUBRESOURCE map = {};
+ V(pCtx->Map(m_pCbufShader, 0, D3D11_MAP_WRITE_DISCARD, 0, &map));
+ memcpy(map.pData, pMtl->m_constants, sizeof(pMtl->m_constants));
+ pCtx->Unmap(m_pCbufShader, 0);
+}
+
+void CShaderManager::UnbindTess(ID3D11DeviceContext * pCtx)
+{
+ pCtx->HSSetShader(nullptr, nullptr, 0);
+ pCtx->DSSetShader(nullptr, nullptr, 0);
+ pCtx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+}
+
+
+void CShaderManager::DiscardRuntimeCompiledShaders()
+{
+ for (std::unordered_map<SHDFEATURES, ID3D11PixelShader *>::iterator
+ i = m_mapSkinFeaturesToShader.begin(), end = m_mapSkinFeaturesToShader.end();
+ i != end;
+ ++i)
+ {
+ if (i->second)
+ i->second->Release();
+ }
+ m_mapSkinFeaturesToShader.clear();
+
+ for (std::unordered_map<SHDFEATURES, ID3D11PixelShader *>::iterator
+ i = m_mapEyeFeaturesToShader.begin(), end = m_mapEyeFeaturesToShader.end();
+ i != end;
+ ++i)
+ {
+ if (i->second)
+ i->second->Release();
+ }
+ m_mapEyeFeaturesToShader.clear();
+}
+
+void CShaderManager::Release()
+{
+ if (m_pPsCopy)
+ {
+ m_pPsCopy->Release();
+ m_pPsCopy = nullptr;
+ }
+ if (m_pPsCreateVSM)
+ {
+ m_pPsCreateVSM->Release();
+ m_pPsCreateVSM = nullptr;
+ }
+ if (m_pVsCurvature)
+ {
+ m_pVsCurvature->Release();
+ m_pVsCurvature = nullptr;
+ }
+ if (m_pPsCurvature)
+ {
+ m_pPsCurvature->Release();
+ m_pPsCurvature = nullptr;
+ }
+ if (m_pPsThickness)
+ {
+ m_pPsThickness->Release();
+ m_pPsThickness = nullptr;
+ }
+ if (m_pPsGaussian)
+ {
+ m_pPsGaussian->Release();
+ m_pPsGaussian = nullptr;
+ }
+ if (m_pPsHair)
+ {
+ m_pPsHair->Release();
+ m_pPsHair = nullptr;
+ }
+ if (m_pVsScreen)
+ {
+ m_pVsScreen->Release();
+ m_pVsScreen = nullptr;
+ }
+ if (m_pVsShadow)
+ {
+ m_pVsShadow->Release();
+ m_pVsShadow = nullptr;
+ }
+ if (m_pVsSkybox)
+ {
+ m_pVsSkybox->Release();
+ m_pVsSkybox = nullptr;
+ }
+ if (m_pPsSkybox)
+ {
+ m_pPsSkybox->Release();
+ m_pPsSkybox = nullptr;
+ }
+ if (m_pVsTess)
+ {
+ m_pVsTess->Release();
+ m_pVsTess = nullptr;
+ }
+ if (m_pHsTess)
+ {
+ m_pHsTess->Release();
+ m_pHsTess = nullptr;
+ }
+ if (m_pDsTess)
+ {
+ m_pDsTess->Release();
+ m_pDsTess = nullptr;
+ }
+ if (m_pVsWorld)
+ {
+ m_pVsWorld->Release();
+ m_pVsWorld = nullptr;
+ }
+
+ if (m_pSsPointClamp)
+ {
+ m_pSsPointClamp->Release();
+ m_pSsPointClamp = nullptr;
+ }
+ if (m_pSsBilinearClamp)
+ {
+ m_pSsBilinearClamp->Release();
+ m_pSsBilinearClamp = nullptr;
+ }
+ if (m_pSsTrilinearRepeat)
+ {
+ m_pSsTrilinearRepeat->Release();
+ m_pSsTrilinearRepeat = nullptr;
+ }
+ if (m_pSsTrilinearRepeatAniso)
+ {
+ m_pSsTrilinearRepeatAniso->Release();
+ m_pSsTrilinearRepeatAniso = nullptr;
+ }
+ if (m_pSsPCF)
+ {
+ m_pSsPCF->Release();
+ m_pSsPCF = nullptr;
+ }
+
+ if (m_pInputLayout)
+ {
+ m_pInputLayout->Release();
+ m_pInputLayout = nullptr;
+ }
+
+ if (m_pCbufDebug)
+ {
+ m_pCbufDebug->Release();
+ m_pCbufDebug = nullptr;
+ }
+ if (m_pCbufFrame)
+ {
+ m_pCbufFrame->Release();
+ m_pCbufFrame = nullptr;
+ }
+ if (m_pCbufShader)
+ {
+ m_pCbufShader->Release();
+ m_pCbufShader = nullptr;
+ }
+
+ DiscardRuntimeCompiledShaders();
+}
diff --git a/samples/d3d11/shader.h b/samples/d3d11/shader.h
new file mode 100644
index 0000000..b826492
--- /dev/null
+++ b/samples/d3d11/shader.h
@@ -0,0 +1,219 @@
+//----------------------------------------------------------------------------------
+// File: FaceWorks/samples/sample_d3d11/shader.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.
+//
+//----------------------------------------------------------------------------------
+
+#pragma once
+
+#include "GFSDK_FaceWorks.h"
+#include <unordered_map>
+#include <d3d11.h>
+#include <DirectXMath.h>
+
+
+
+
+// Shader feature flags
+enum SHDFEAT
+{
+ SHDFEAT_None = 0x00,
+ SHDFEAT_Tessellation = 0x01,
+ SHDFEAT_SSS = 0x02,
+ SHDFEAT_DeepScatter = 0x04,
+
+ SHDFEAT_PSMask = 0x06, // Features that affect the pixel shader
+};
+typedef int SHDFEATURES;
+
+
+
+// Constant buffers
+
+struct CbufDebug // matches cbuffer cbDebug in common.hlsli
+{
+ float m_debug; // Mapped to spacebar - 0 if up, 1 if down
+ float m_debugSlider0; // Mapped to debug slider in UI
+ float m_debugSlider1; // ...
+ float m_debugSlider2; // ...
+ float m_debugSlider3; // ...
+};
+
+struct CbufFrame // matches cbuffer cbFrame in lighting.hlsli
+{
+ DirectX::XMFLOAT4X4 m_matWorldToClip;
+ DirectX::XMFLOAT4 m_posCamera;
+
+ DirectX::XMFLOAT4 m_vecDirectionalLight;
+ DirectX::XMFLOAT4 m_rgbDirectionalLight;
+
+ DirectX::XMFLOAT4X4 m_matWorldToUvzwShadow;
+ DirectX::XMFLOAT4 m_matWorldToUvzShadowNormal[3]; // Matrix for transforming normals to shadow map space
+
+ float m_vsmMinVariance; // Minimum variance for variance shadow maps
+ float m_shadowSharpening;
+ float m_tessScale; // Scale of adaptive tessellation
+
+ float m_deepScatterIntensity; // Multiplier on whole deep scattering result
+ float m_deepScatterFalloff; // Reciprocal of one-sigma radius of deep scatter Gaussian, in cm
+ float m_deepScatterNormalOffset; // Normal offset for shadow lookup to calculate thickness
+
+ float m_exposure; // Exposure multiplier
+};
+
+
+
+// Material model - textures and constants for a particular material
+
+enum SHADER
+{
+ SHADER_Skin,
+ SHADER_Eye,
+ SHADER_Hair,
+};
+
+struct Material
+{
+ SHADER m_shader; // Which shader is this?
+
+ ID3D11ShaderResourceView *
+ m_aSrv[4]; // Textures
+ int m_textureSlots[4]; // Slots where to bind the textures
+ float m_constants[24]; // Data for CB_SHADER constant buffer - includes
+ // FaceWorks constant buffer data as well
+};
+
+
+
+// Shader data and loading
+
+class CShaderManager
+{
+public:
+ ID3D11PixelShader * m_pPsCopy;
+ ID3D11PixelShader * m_pPsCreateVSM;
+ ID3D11VertexShader * m_pVsCurvature;
+ ID3D11PixelShader * m_pPsCurvature;
+ ID3D11PixelShader * m_pPsThickness;
+ ID3D11PixelShader * m_pPsGaussian;
+ ID3D11PixelShader * m_pPsHair;
+ ID3D11VertexShader * m_pVsScreen;
+ ID3D11VertexShader * m_pVsShadow;
+ ID3D11VertexShader * m_pVsSkybox;
+ ID3D11PixelShader * m_pPsSkybox;
+ ID3D11VertexShader * m_pVsTess;
+ ID3D11HullShader * m_pHsTess;
+ ID3D11DomainShader * m_pDsTess;
+ ID3D11VertexShader * m_pVsWorld;
+
+ ID3D11SamplerState * m_pSsPointClamp;
+ ID3D11SamplerState * m_pSsBilinearClamp;
+ ID3D11SamplerState * m_pSsTrilinearRepeat;
+ ID3D11SamplerState * m_pSsTrilinearRepeatAniso;
+ ID3D11SamplerState * m_pSsPCF;
+
+ ID3D11InputLayout * m_pInputLayout;
+
+ ID3D11Buffer * m_pCbufDebug;
+ ID3D11Buffer * m_pCbufFrame;
+ ID3D11Buffer * m_pCbufShader;
+
+ CShaderManager();
+
+ HRESULT Init(ID3D11Device * pDevice);
+
+ void InitFrame(
+ ID3D11DeviceContext * pCtx,
+ const CbufDebug * pCbufDebug,
+ const CbufFrame * pCbufFrame,
+ ID3D11ShaderResourceView * pSrvCubeDiffuse,
+ ID3D11ShaderResourceView * pSrvCubeSpec,
+ ID3D11ShaderResourceView * pSrvCurvatureLUT,
+ ID3D11ShaderResourceView * pSrvShadowLUT);
+
+ void BindShadowTextures(
+ ID3D11DeviceContext * pCtx,
+ ID3D11ShaderResourceView * pSrvShadowMap,
+ ID3D11ShaderResourceView * pSrvVSM);
+
+ ID3D11PixelShader * GetSkinShader(ID3D11Device * pDevice, SHDFEATURES features);
+ ID3D11PixelShader * GetEyeShader(ID3D11Device * pDevice, SHDFEATURES features);
+
+ void BindCopy(
+ ID3D11DeviceContext * pCtx,
+ ID3D11ShaderResourceView * pSrvSrc,
+ const DirectX::XMFLOAT4X4 & matTransformColor);
+ void BindCreateVSM(
+ ID3D11DeviceContext * pCtx,
+ ID3D11ShaderResourceView * pSrvSrc);
+ void BindCurvature(
+ ID3D11DeviceContext * pCtx,
+ float curvatureScale,
+ float curvatureBias);
+ void BindThickness(
+ ID3D11DeviceContext * pCtx,
+ GFSDK_FaceWorks_CBData * pFaceWorksCBData);
+ void BindGaussian(
+ ID3D11DeviceContext * pCtx,
+ ID3D11ShaderResourceView * pSrvSrc,
+ float blurX,
+ float blurY);
+ void BindShadow(
+ ID3D11DeviceContext * pCtx,
+ const DirectX::XMFLOAT4X4 & matWorldToClipShadow);
+ void BindSkybox(
+ ID3D11DeviceContext * pCtx,
+ ID3D11ShaderResourceView * pSrvSkybox,
+ const DirectX::XMFLOAT4X4 & matClipToWorldAxes);
+
+ void BindMaterial(
+ ID3D11DeviceContext * pCtx,
+ SHDFEATURES features,
+ const Material * pMtl);
+ void UnbindTess(ID3D11DeviceContext * pCtx);
+
+ void DiscardRuntimeCompiledShaders();
+ void Release();
+
+private:
+
+ bool CompileShader(
+ ID3D11Device * pDevice,
+ const char * source,
+ ID3D11PixelShader ** ppPsOut);
+ void CreateSkinShader(ID3D11Device * pDevice, SHDFEATURES features);
+ void CreateEyeShader(ID3D11Device * pDevice, SHDFEATURES features);
+
+ std::unordered_map<SHDFEATURES, ID3D11PixelShader *> m_mapSkinFeaturesToShader;
+ std::unordered_map<SHDFEATURES, ID3D11PixelShader *> m_mapEyeFeaturesToShader;
+};
+
+extern CShaderManager g_shdmgr;
diff --git a/samples/d3d11/shaders/common.hlsli b/samples/d3d11/shaders/common.hlsli
new file mode 100644
index 0000000..8651031
--- /dev/null
+++ b/samples/d3d11/shaders/common.hlsli
@@ -0,0 +1,97 @@
+//----------------------------------------------------------------------------------
+// File: FaceWorks/samples/sample_d3d11/shaders/common.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 COMMON_HLSLI
+#define COMMON_HLSLI
+
+#pragma pack_matrix(row_major)
+
+#include "resources.h"
+
+struct Vertex
+{
+ float3 m_pos : POSITION;
+ float3 m_normal : NORMAL;
+ float2 m_uv : UV;
+ float3 m_tangent : TANGENT;
+ float m_curvature : CURVATURE;
+};
+
+cbuffer cbDebug : CB_DEBUG // matches struct CbufDebug in util.h
+{
+ float g_debug; // Mapped to spacebar - 0 if up, 1 if down
+ float g_debugSlider0; // Mapped to debug slider in UI
+ float g_debugSlider1; // ...
+ float g_debugSlider2; // ...
+ float g_debugSlider3; // ...
+}
+
+cbuffer cbFrame : CB_FRAME // matches struct CbufFrame in util.h
+{
+ float4x4 g_matWorldToClip;
+ float3 g_posCamera;
+
+ float3 g_vecDirectionalLight;
+ float3 g_rgbDirectionalLight;
+
+ float4x4 g_matWorldToUvzwShadow;
+ float3x3 g_matWorldToUvzShadowNormal; // Matrix for transforming normals to shadow map space
+ float dummy; // Padding
+
+ float g_vsmMinVariance; // Minimum variance for variance shadow maps
+ float g_shadowSharpening;
+ float g_tessScale; // Scale of adaptive tessellation
+
+ float g_deepScatterIntensity; // Multiplier on whole deep scattering result
+ float g_deepScatterNormalOffset; // Normal offset for shadow lookup to calculate thickness
+
+ float g_exposure; // Exposure multiplier
+}
+
+TextureCube<float3> g_texCubeDiffuse : TEX_CUBE_DIFFUSE;
+TextureCube<float3> g_texCubeSpec : TEX_CUBE_SPEC;
+Texture2D<float> g_texShadowMap : TEX_SHADOW_MAP;
+Texture2D<float2> g_texVSM : TEX_VSM;
+Texture2D g_texCurvatureLUT : TEX_CURVATURE_LUT;
+Texture2D g_texShadowLUT : TEX_SHADOW_LUT;
+
+SamplerState g_ssPointClamp : SAMP_POINT_CLAMP;
+SamplerState g_ssBilinearClamp : SAMP_BILINEAR_CLAMP;
+SamplerState g_ssTrilinearRepeat : SAMP_TRILINEAR_REPEAT;
+SamplerState g_ssTrilinearRepeatAniso : SAMP_TRILINEAR_REPEAT_ANISO;
+SamplerComparisonState g_scsPCF : SAMP_PCF;
+
+float square(float x) { return x*x; }
+
+#endif // COMMON_HLSLI
diff --git a/samples/d3d11/shaders/copy_ps.hlsl b/samples/d3d11/shaders/copy_ps.hlsl
new file mode 100644
index 0000000..6e79416
--- /dev/null
+++ b/samples/d3d11/shaders/copy_ps.hlsl
@@ -0,0 +1,48 @@
+//----------------------------------------------------------------------------------
+// File: FaceWorks/samples/sample_d3d11/shaders/copy_ps.hlsl
+// 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.
+//
+//----------------------------------------------------------------------------------
+
+
+#include "common.hlsli"
+
+cbuffer cbShader : CB_SHADER
+{
+ float4x4 g_matTransformColor;
+}
+
+Texture2D g_texSource : TEX_SOURCE;
+
+float4 main(in float2 i_uv : UV) : SV_Target
+{
+ return mul(g_texSource.Sample(g_ssTrilinearRepeat, i_uv), g_matTransformColor);
+}
diff --git a/samples/d3d11/shaders/create_vsm_ps.hlsl b/samples/d3d11/shaders/create_vsm_ps.hlsl
new file mode 100644
index 0000000..9736891
--- /dev/null
+++ b/samples/d3d11/shaders/create_vsm_ps.hlsl
@@ -0,0 +1,43 @@
+//----------------------------------------------------------------------------------
+// File: FaceWorks/samples/sample_d3d11/shaders/create_vsm_ps.hlsl
+// 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.
+//
+//----------------------------------------------------------------------------------
+
+#include "common.hlsli"
+
+Texture2D<float> g_texSource : TEX_SOURCE;
+
+float2 main(in float2 i_uv : UV) : SV_Target
+{
+ float z = g_texSource.Sample(g_ssPointClamp, i_uv);
+ return float2(z, z*z);
+}
diff --git a/samples/d3d11/shaders/curvature_ps.hlsl b/samples/d3d11/shaders/curvature_ps.hlsl
new file mode 100644
index 0000000..e4de321
--- /dev/null
+++ b/samples/d3d11/shaders/curvature_ps.hlsl
@@ -0,0 +1,42 @@
+//----------------------------------------------------------------------------------
+// File: FaceWorks/samples/sample_d3d11/shaders/curvature_ps.hlsl
+// 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.
+//
+//----------------------------------------------------------------------------------
+
+#include "common.hlsli"
+
+void main(
+ in float i_color : COLOR,
+ out float4 o_rgba : SV_Target)
+{
+ o_rgba = float4(i_color.xxx, 1.0);
+}
diff --git a/samples/d3d11/shaders/curvature_vs.hlsl b/samples/d3d11/shaders/curvature_vs.hlsl
new file mode 100644
index 0000000..b14f5fa
--- /dev/null
+++ b/samples/d3d11/shaders/curvature_vs.hlsl
@@ -0,0 +1,49 @@
+//----------------------------------------------------------------------------------
+// File: FaceWorks/samples/sample_d3d11/shaders/curvature_vs.hlsl
+// 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.
+//
+//----------------------------------------------------------------------------------
+
+#include "common.hlsli"
+
+cbuffer cbShader : CB_SHADER
+{
+ float2 g_curvatureScaleBias;
+}
+
+void main(
+ in Vertex i_vtx,
+ out float o_color : COLOR,
+ out float4 o_posClip : SV_Position)
+{
+ o_color = sqrt(i_vtx.m_curvature * g_curvatureScaleBias.x + g_curvatureScaleBias.y);
+ o_posClip = mul(float4(i_vtx.m_pos, 1.0), g_matWorldToClip);
+}
diff --git a/samples/d3d11/shaders/eye.hlsli b/samples/d3d11/shaders/eye.hlsli
new file mode 100644
index 0000000..65919cf
--- /dev/null
+++ b/samples/d3d11/shaders/eye.hlsli
@@ -0,0 +1,132 @@
+//----------------------------------------------------------------------------------
+// File: FaceWorks/samples/sample_d3d11/shaders/eye.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 EYE_HLSLI
+#define EYE_HLSLI
+
+#include "common.hlsli"
+#include "lighting.hlsli"
+#include "GFSDK_FaceWorks.hlsli"
+
+#pragma warning(disable: 3571) // pow() doesn't handle negative numbers
+
+cbuffer cbShader : CB_SHADER
+{
+ float g_normalStrength;
+ float g_specReflectance;
+ float g_gloss;
+ float3 g_rgbDeepScatter;
+
+ // Iris parameters
+ float g_irisRadiusSource; // Radius of iris in iris texture (in UV units)
+ float g_irisRadiusDest; // Radius of iris in schlera texture (in UV units)
+ float g_irisEdgeHardness; // Controls hardness/softness of iris edge
+ float g_irisDilation; // How much the iris is dilated
+
+ GFSDK_FaceWorks_CBData g_faceworksData;
+}
+
+Texture2D<float3> g_texDiffuseSclera : TEX_DIFFUSE0;
+Texture2D<float3> g_texDiffuseIris : TEX_DIFFUSE1;
+Texture2D<float3> g_texNormal : TEX_NORMAL;
+
+
+
+void EyeMegashader(
+ in Vertex i_vtx,
+ in float3 i_vecCamera,
+ in float4 i_uvzwShadow,
+ out float3 o_rgbLit,
+ uniform bool useSSS,
+ uniform bool useDeepScatter)
+{
+ float2 uv = i_vtx.m_uv;
+
+ // Calculate diffuse color, overlaying iris on sclera
+
+ float3 rgbDiffuse = g_texDiffuseSclera.Sample(g_ssTrilinearRepeatAniso, uv);
+ float irisAlpha = 0.0;
+
+ float radiusDest = length(uv - 0.5.xx);
+ if (radiusDest < g_irisRadiusDest)
+ {
+ // Use a power function to remap the radius, to simulate dilation of the iris
+ float radiusSource = (1.0 - pow(1.0 - radiusDest / g_irisRadiusDest, 1.0 - g_irisDilation)) * g_irisRadiusSource;
+ float2 uvIris = (uv - 0.5.xx) * (radiusSource / radiusDest) + 0.5.xx;
+ float3 rgbIris = g_texDiffuseIris.Sample(g_ssTrilinearRepeatAniso, uvIris);
+
+ // Calculate alpha using a smoothstep-like falloff at the edge of the iris
+ irisAlpha = saturate((g_irisRadiusDest - radiusDest) * g_irisEdgeHardness);
+ irisAlpha = (3.0 - 2.0 * irisAlpha) * square(irisAlpha);
+ rgbDiffuse = lerp(rgbDiffuse, rgbIris, irisAlpha);
+ }
+
+ // Sample other textures
+ float3 normalTangent = UnpackNormal(g_texNormal.Sample(g_ssTrilinearRepeatAniso, uv),
+ g_normalStrength);
+
+ float3 normalTangentBlurred;
+ if (useSSS || useDeepScatter)
+ {
+ // Sample normal map with level clamped based on blur, to get normal for SSS
+ float level = GFSDK_FaceWorks_CalculateMipLevelForBlurredNormal(
+ g_faceworksData, g_texNormal, g_ssTrilinearRepeatAniso, uv);
+ normalTangentBlurred = UnpackNormal(
+ g_texNormal.SampleLevel(g_ssTrilinearRepeatAniso, uv, level),
+ g_normalStrength);
+ }
+
+ // Lerp normals to flat, and gloss to 1.0 in the iris region
+ normalTangent = lerp(normalTangent, float3(0, 0, 1), irisAlpha);
+ normalTangentBlurred = lerp(normalTangentBlurred, float3(0, 0, 1), irisAlpha);
+ float gloss = lerp(g_gloss, 1.0, irisAlpha);
+
+ LightingMegashader(
+ i_vtx,
+ i_vecCamera,
+ i_uvzwShadow,
+ rgbDiffuse,
+ normalTangent,
+ normalTangentBlurred,
+ g_specReflectance,
+ gloss,
+ g_rgbDeepScatter,
+ g_faceworksData,
+ o_rgbLit,
+ true, // useNormalMap
+ useSSS,
+ useDeepScatter);
+}
+
+#endif // EYE_HLSLI
diff --git a/samples/d3d11/shaders/gaussian_ps.hlsl b/samples/d3d11/shaders/gaussian_ps.hlsl
new file mode 100644
index 0000000..7d3f81f
--- /dev/null
+++ b/samples/d3d11/shaders/gaussian_ps.hlsl
@@ -0,0 +1,91 @@
+//----------------------------------------------------------------------------------
+// File: FaceWorks/samples/sample_d3d11/shaders/gaussian_ps.hlsl
+// 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.
+//
+//----------------------------------------------------------------------------------
+
+#include "common.hlsli"
+
+cbuffer cbShader : CB_SHADER
+{
+ float2 g_vecBlur;
+}
+
+Texture2D<float2> g_texSrc : TEX_SOURCE;
+
+// Gaussian blur coefficients - x = weight, y = position offset
+// Python code to generate:
+// import math
+// n = 21
+// points = [-3.0 + 6.0 * float(i) / float(n - 1) for i in range(n)]
+// weights = [math.exp(-0.5 * x**2) for x in points]
+// weightSum = sum(weights)
+// print(("static const float2 s_aGaussian%d[] =\n{\n" % n) + ''.join(
+// " { %0.5f, %4.2f },\n" % (weights[i]/weightSum, points[i]) for i in range(n)) + "};")
+
+static const float2 s_aGaussian21[] =
+{
+ { 0.00133, -3.00 },
+ { 0.00313, -2.70 },
+ { 0.00673, -2.40 },
+ { 0.01322, -2.10 },
+ { 0.02372, -1.80 },
+ { 0.03892, -1.50 },
+ { 0.05835, -1.20 },
+ { 0.07995, -0.90 },
+ { 0.10012, -0.60 },
+ { 0.11460, -0.30 },
+ { 0.11987, 0.00 },
+ { 0.11460, 0.30 },
+ { 0.10012, 0.60 },
+ { 0.07995, 0.90 },
+ { 0.05835, 1.20 },
+ { 0.03892, 1.50 },
+ { 0.02372, 1.80 },
+ { 0.01322, 2.10 },
+ { 0.00673, 2.40 },
+ { 0.00313, 2.70 },
+ { 0.00133, 3.00 },
+};
+
+float2 main(in float2 i_uv : UV) : SV_Target
+{
+ float2 sum = 0.0;
+
+ [unroll] for (int i = 0; i < 21; ++i)
+ {
+ float weight = s_aGaussian21[i].x;
+ float2 offset = s_aGaussian21[i].y * g_vecBlur;
+ sum += weight * g_texSrc.Sample(g_ssBilinearClamp, i_uv + offset);
+ }
+
+ return sum;
+}
diff --git a/samples/d3d11/shaders/hair_ps.hlsl b/samples/d3d11/shaders/hair_ps.hlsl
new file mode 100644
index 0000000..c2fb2ac
--- /dev/null
+++ b/samples/d3d11/shaders/hair_ps.hlsl
@@ -0,0 +1,82 @@
+//----------------------------------------------------------------------------------
+// File: FaceWorks/samples/sample_d3d11/shaders/hair_ps.hlsl
+// 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.
+//
+//----------------------------------------------------------------------------------
+
+#include "common.hlsli"
+#include "lighting.hlsli"
+
+cbuffer cbShader : CB_SHADER
+{
+ float g_specReflectance;
+ float g_gloss;
+}
+
+Texture2D<float4> g_texDiffuse : TEX_DIFFUSE0;
+
+void main(
+ in Vertex i_vtx,
+ in float3 i_vecCamera : CAMERA,
+ in float4 i_uvzwShadow : UVZW_SHADOW,
+ in bool front : SV_IsFrontFace,
+ out float4 o_rgbaLit : SV_Target)
+{
+ float2 uv = i_vtx.m_uv;
+
+ // Sample textures
+
+ float4 rgbaDiffuse = g_texDiffuse.Sample(g_ssTrilinearRepeatAniso, uv);
+
+ // Perform lighting
+
+ if (!front)
+ i_vtx.m_normal = -i_vtx.m_normal;
+
+ LightingMegashader(
+ i_vtx,
+ i_vecCamera,
+ i_uvzwShadow,
+ rgbaDiffuse.rgb,
+ 0.0.xxx,
+ 0.0.xxx,
+ g_specReflectance,
+ g_gloss,
+ 0.0.xxx,
+ (GFSDK_FaceWorks_CBData)0,
+ o_rgbaLit.rgb,
+ false, // useNormalMap
+ false, // useSSS
+ false); // useDeepScatter
+
+ // Write texture alpha for transparency
+ o_rgbaLit.a = rgbaDiffuse.a;
+}
diff --git a/samples/d3d11/shaders/lighting.hlsli b/samples/d3d11/shaders/lighting.hlsli
new file mode 100644
index 0000000..52258d2
--- /dev/null
+++ b/samples/d3d11/shaders/lighting.hlsli
@@ -0,0 +1,293 @@
+//----------------------------------------------------------------------------------
+// File: FaceWorks/samples/sample_d3d11/shaders/lighting.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 LIGHTING_HLSLI
+#define LIGHTING_HLSLI
+
+#include "common.hlsli"
+#include "tonemap.hlsli"
+#include "GFSDK_FaceWorks.hlsli"
+
+
+
+// Normal mapping
+
+float3 UnpackNormal(
+ float3 sample,
+ float normalStrength)
+{
+ return lerp(float3(0, 0, 1),
+ sample * 2.0 - 1.0,
+ normalStrength);
+}
+
+
+
+// Shadow filtering, using variance shadow maps
+
+float EvaluateShadowVSM(
+ float4 uvzwShadow,
+ float3 normalGeom)
+{
+ float3 uvzShadow = uvzwShadow.xyz / uvzwShadow.w;
+
+ float2 vsmValue = g_texVSM.Sample(g_ssBilinearClamp, uvzShadow.xy);
+ float mean = vsmValue.x;
+ float variance = max(g_vsmMinVariance, vsmValue.y - mean*mean);
+
+ return saturate(variance / (variance + square(uvzShadow.z - mean)));
+}
+
+
+
+// Diffuse lighting
+
+float3 EvaluateDiffuseLight(
+ float3 normalGeom,
+ float3 normalShade,
+ float shadow)
+{
+ // Directional light diffuse
+ float NdotL = saturate(dot(normalShade, g_vecDirectionalLight));
+ float3 rgbLightDiffuse = g_rgbDirectionalLight * (NdotL * shadow);
+
+ // IBL diffuse
+ rgbLightDiffuse += g_texCubeDiffuse.Sample(g_ssTrilinearRepeat, normalShade);
+
+ return rgbLightDiffuse;
+}
+
+float3 EvaluateSSSDiffuseLight(
+ float3 normalGeom,
+ float3 normalShade,
+ float3 normalBlurred,
+ float shadow,
+ float curvature,
+ GFSDK_FaceWorks_CBData faceworksData)
+{
+ // Directional light diffuse
+ float3 rgbSSS = GFSDK_FaceWorks_EvaluateSSSDirectLight(
+ faceworksData,
+ normalGeom, normalShade, normalBlurred,
+ g_vecDirectionalLight, curvature,
+ g_texCurvatureLUT, g_ssBilinearClamp);
+ float3 rgbShadow = GFSDK_FaceWorks_EvaluateSSSShadow(
+ faceworksData,
+ normalGeom, g_vecDirectionalLight, shadow,
+ g_texShadowLUT, g_ssBilinearClamp);
+ float3 rgbLightDiffuse = g_rgbDirectionalLight * rgbSSS * rgbShadow;
+
+ // IBL diffuse
+ float3 normalAmbient0, normalAmbient1, normalAmbient2;
+ GFSDK_FaceWorks_CalculateNormalsForAmbientLight(
+ normalShade, normalBlurred,
+ normalAmbient0, normalAmbient1, normalAmbient2);
+ float3 rgbAmbient0 = g_texCubeDiffuse.Sample(g_ssTrilinearRepeat, normalAmbient0);
+ float3 rgbAmbient1 = g_texCubeDiffuse.Sample(g_ssTrilinearRepeat, normalAmbient1);
+ float3 rgbAmbient2 = g_texCubeDiffuse.Sample(g_ssTrilinearRepeat, normalAmbient2);
+ rgbLightDiffuse += GFSDK_FaceWorks_EvaluateSSSAmbientLight(
+ rgbAmbient0, rgbAmbient1, rgbAmbient2);
+
+ return rgbLightDiffuse;
+}
+
+
+
+// Specular lighting
+
+float3 EvaluateSpecularLight(
+ float3 normalGeom,
+ float3 normalShade,
+ float3 vecCamera,
+ float specReflectance,
+ float gloss,
+ float shadow)
+{
+ // Directional light spec
+
+ float3 vecHalf = normalize(g_vecDirectionalLight + vecCamera);
+ float NdotL = saturate(dot(normalShade, g_vecDirectionalLight));
+ float NdotH = saturate(dot(normalShade, vecHalf));
+ float LdotH = dot(g_vecDirectionalLight, vecHalf);
+ float NdotV = saturate(dot(normalShade, vecCamera));
+ float specPower = exp2(gloss * 13.0);
+
+ // Evaluate NDF and visibility function:
+ // Two-lobe Blinn-Phong, with double gloss on second lobe
+ float specLobeBlend = 0.05;
+ float specPower0 = specPower;
+ float specPower1 = square(specPower);
+ float ndf0 = pow(NdotH, specPower0) * (specPower0 + 2.0) * 0.5;
+ float schlickSmithFactor0 = rsqrt(specPower0 * (3.14159 * 0.25) + (3.14159 * 0.5));
+ float visibilityFn0 = 0.25 / (lerp(schlickSmithFactor0, 1, NdotL) *
+ lerp(schlickSmithFactor0, 1, NdotV));
+ float ndf1 = pow(NdotH, specPower1) * (specPower1 + 2.0) * 0.5;
+ float schlickSmithFactor1 = rsqrt(specPower1 * (3.14159 * 0.25) + (3.14159 * 0.5));
+ float visibilityFn1 = 0.25 / (lerp(schlickSmithFactor1, 1, NdotL) *
+ lerp(schlickSmithFactor1, 1, NdotV));
+ float ndfResult = lerp(ndf0 * visibilityFn0, ndf1 * visibilityFn1, specLobeBlend);
+
+ float fresnel = lerp(specReflectance, 1.0, pow(1.0 - LdotH, 5.0));
+ float specResult = ndfResult * fresnel;
+ // Darken spec where the *geometric* NdotL gets too low -
+ // avoids it showing up on bumps in shadowed areas
+ float edgeDarken = saturate(5.0 * dot(normalGeom, g_vecDirectionalLight));
+ float3 rgbLitSpecular = g_rgbDirectionalLight * (NdotL * edgeDarken * specResult * shadow);
+
+ // IBL spec - again two-lobe
+ float3 vecReflect = reflect(-vecCamera, normalShade);
+ float gloss0 = gloss;
+ float gloss1 = saturate(2.0 * gloss);
+ float fresnelIBL0 = lerp(specReflectance, 1.0,
+ pow(1.0 - NdotV, 5.0) / (-3.0 * gloss0 + 4.0));
+ float mipLevel0 = -9.0 * gloss0 + 9.0;
+ float3 iblSpec0 = fresnelIBL0 * g_texCubeSpec.SampleLevel(
+ g_ssTrilinearRepeat, vecReflect, mipLevel0);
+ float fresnelIBL1 = lerp(specReflectance, 1.0,
+ pow(1.0 - NdotV, 5.0) / (-3.0 * gloss1 + 4.0));
+ float mipLevel1 = -9.0 * gloss1 + 9.0;
+ float3 iblSpec1 = fresnelIBL1 * g_texCubeSpec.SampleLevel(
+ g_ssTrilinearRepeat, vecReflect, mipLevel1);
+ rgbLitSpecular += lerp(iblSpec0, iblSpec1, specLobeBlend);
+
+ return rgbLitSpecular;
+}
+
+
+
+// Master lighting routine
+
+void LightingMegashader(
+ in Vertex i_vtx,
+ in float3 i_vecCamera,
+ in float4 i_uvzwShadow,
+ in float3 rgbDiffuse,
+ in float3 normalTangent,
+ in float3 normalTangentBlurred,
+ in float specReflectance,
+ in float gloss,
+ in float3 rgbDeepScatter,
+ in GFSDK_FaceWorks_CBData faceworksData,
+ out float3 o_rgbLit,
+ uniform bool useNormalMap,
+ uniform bool useSSS,
+ uniform bool useDeepScatter)
+{
+ float3 normalGeom = normalize(i_vtx.m_normal);
+ float3 vecCamera = normalize(i_vecCamera);
+ float2 uv = i_vtx.m_uv;
+
+ float3 normalShade, normalBlurred;
+ if (useNormalMap)
+ {
+ // Transform normal maps to world space
+
+ float3x3 matTangentToWorld = float3x3(
+ normalize(i_vtx.m_tangent),
+ normalize(cross(normalGeom, i_vtx.m_tangent)),
+ normalGeom);
+
+ normalShade = normalize(mul(normalTangent, matTangentToWorld));
+
+ if (useSSS || useDeepScatter)
+ {
+ normalBlurred = normalize(mul(normalTangentBlurred, matTangentToWorld));
+ }
+ }
+ else
+ {
+ normalShade = normalGeom;
+ normalBlurred = normalGeom;
+ }
+
+ // Evaluate shadow map
+ float shadow = EvaluateShadowVSM(i_uvzwShadow, normalGeom);
+
+ float3 rgbLitDiffuse;
+ if (useSSS)
+ {
+ // Evaluate diffuse lighting
+ float3 rgbDiffuseLight = EvaluateSSSDiffuseLight(
+ normalGeom, normalShade, normalBlurred,
+ shadow, i_vtx.m_curvature, faceworksData);
+ rgbLitDiffuse = rgbDiffuseLight * rgbDiffuse;
+
+ // Remap shadow to 1/3-as-wide penumbra to match shadow from LUT.
+ shadow = GFSDK_FaceWorks_SharpenShadow(shadow, g_shadowSharpening);
+ }
+ else
+ {
+ // Remap shadow to 1/3-as-wide penumbra to match shadow in SSS case.
+ shadow = GFSDK_FaceWorks_SharpenShadow(shadow, g_shadowSharpening);
+
+ // Evaluate diffuse lighting
+ float3 rgbDiffuseLight = EvaluateDiffuseLight(normalGeom, normalShade, shadow);
+ rgbLitDiffuse = rgbDiffuseLight * rgbDiffuse;
+ }
+
+ // Evaluate specular lighting
+ float3 rgbLitSpecular = EvaluateSpecularLight(
+ normalGeom, normalShade, vecCamera,
+ specReflectance, gloss,
+ shadow);
+
+ // Put it all together
+ o_rgbLit = rgbLitDiffuse + rgbLitSpecular;
+
+ if (useDeepScatter)
+ {
+ float3 uvzShadow = i_uvzwShadow.xyz / i_uvzwShadow.w;
+
+ // Apply normal offset to avoid silhouette edge artifacts
+ // !!!UNDONE: move this to vertex shader
+ float3 normalShadow = mul(normalGeom, g_matWorldToUvzShadowNormal);
+ uvzShadow += normalShadow * g_deepScatterNormalOffset;
+
+ float thickness = GFSDK_FaceWorks_EstimateThicknessFromParallelShadowPoisson32(
+ faceworksData,
+ g_texShadowMap, g_ssBilinearClamp, uvzShadow);
+
+ float deepScatterFactor = GFSDK_FaceWorks_EvaluateDeepScatterDirectLight(
+ faceworksData,
+ normalBlurred, g_vecDirectionalLight, thickness);
+ rgbDeepScatter *= g_deepScatterIntensity;
+ o_rgbLit += (g_deepScatterIntensity * deepScatterFactor) * rgbDeepScatter *
+ rgbDiffuse * g_rgbDirectionalLight;
+ }
+
+ // Apply tonemapping to the result
+ o_rgbLit = Tonemap(o_rgbLit);
+}
+
+#endif // LIGHTING_HLSLI
diff --git a/samples/d3d11/shaders/resources.h b/samples/d3d11/shaders/resources.h
new file mode 100644
index 0000000..3226c8d
--- /dev/null
+++ b/samples/d3d11/shaders/resources.h
@@ -0,0 +1,75 @@
+//----------------------------------------------------------------------------------
+// File: FaceWorks/samples/sample_d3d11/shaders/resources.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.
+//
+//----------------------------------------------------------------------------------
+
+#ifndef RESOURCES_H
+#define RESOURCES_H
+
+// This file is included from both C++ and HLSL; it defines shared resource slot assignments
+
+#ifdef __cplusplus
+# define CBREG(n) n
+# define TEXREG(n) n
+# define SAMPREG(n) n
+#else
+# define CBREG(n) register(b##n)
+# define TEXREG(n) register(t##n)
+# define SAMPREG(n) register(s##n)
+#endif
+
+#define CB_DEBUG CBREG(0)
+#define CB_FRAME CBREG(1)
+#define CB_SHADER CBREG(2)
+
+#define TEX_CUBE_DIFFUSE TEXREG(0)
+#define TEX_CUBE_SPEC TEXREG(1)
+#define TEX_SHADOW_MAP TEXREG(2)
+#define TEX_VSM TEXREG(3)
+#define TEX_DIFFUSE0 TEXREG(4)
+#define TEX_DIFFUSE1 TEXREG(5)
+#define TEX_NORMAL TEXREG(6)
+#define TEX_SPEC TEXREG(7)
+#define TEX_GLOSS TEXREG(8)
+#define TEX_SSS_MASK TEXREG(9)
+#define TEX_DEEP_SCATTER_COLOR TEXREG(10)
+#define TEX_SOURCE TEXREG(11)
+#define TEX_CURVATURE_LUT TEXREG(12)
+#define TEX_SHADOW_LUT TEXREG(13)
+
+#define SAMP_POINT_CLAMP SAMPREG(0)
+#define SAMP_BILINEAR_CLAMP SAMPREG(1)
+#define SAMP_TRILINEAR_REPEAT SAMPREG(2)
+#define SAMP_TRILINEAR_REPEAT_ANISO SAMPREG(3)
+#define SAMP_PCF SAMPREG(4)
+
+#endif // RESOURCES_H
diff --git a/samples/d3d11/shaders/screen_vs.hlsl b/samples/d3d11/shaders/screen_vs.hlsl
new file mode 100644
index 0000000..c5c945b
--- /dev/null
+++ b/samples/d3d11/shaders/screen_vs.hlsl
@@ -0,0 +1,45 @@
+//----------------------------------------------------------------------------------
+// File: FaceWorks/samples/sample_d3d11/shaders/screen_vs.hlsl
+// 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.
+//
+//----------------------------------------------------------------------------------
+
+
+#include "common.hlsli"
+
+void main(
+ in Vertex i_vtx,
+ out float2 o_uv : UV,
+ out float4 o_posClip : SV_Position)
+{
+ o_posClip = float4(i_vtx.m_pos.xy, 0.0, 1.0);
+ o_uv = i_vtx.m_uv;
+}
diff --git a/samples/d3d11/shaders/shadow_vs.hlsl b/samples/d3d11/shaders/shadow_vs.hlsl
new file mode 100644
index 0000000..f55bb2d
--- /dev/null
+++ b/samples/d3d11/shaders/shadow_vs.hlsl
@@ -0,0 +1,53 @@
+// This code contains NVIDIA Confidential Information and is disclosed
+// under the Mutual Non-Disclosure Agreement.
+//
+// Notice
+// ALL NVIDIA DESIGN SPECIFICATIONS AND CODE ("MATERIALS") ARE PROVIDED "AS IS" NVIDIA MAKES
+// NO REPRESENTATIONS, WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+//----------------------------------------------------------------------------------
+// File: FaceWorks/samples/sample_d3d11/shaders/shadow_vs.hlsl
+// 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.
+//
+//----------------------------------------------------------------------------------
+
+#include "common.hlsli"
+
+cbuffer cbShader : CB_SHADER
+{
+ float4x4 g_matWorldToClipShadow;
+}
+
+void main(
+ in Vertex i_vtx,
+ out float4 o_posClip : SV_Position)
+{
+ o_posClip = mul(float4(i_vtx.m_pos, 1.0), g_matWorldToClipShadow);
+}
diff --git a/samples/d3d11/shaders/skin.hlsli b/samples/d3d11/shaders/skin.hlsli
new file mode 100644
index 0000000..fd4f953
--- /dev/null
+++ b/samples/d3d11/shaders/skin.hlsli
@@ -0,0 +1,108 @@
+//----------------------------------------------------------------------------------
+// File: FaceWorks/samples/sample_d3d11/shaders/skin.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 SKIN_HLSLI
+#define SKIN_HLSLI
+
+#include "common.hlsli"
+#include "lighting.hlsli"
+#include "GFSDK_FaceWorks.hlsli"
+
+cbuffer cbShader : CB_SHADER
+{
+ float g_normalStrength;
+ float g_gloss;
+
+ GFSDK_FaceWorks_CBData g_faceworksData;
+}
+
+Texture2D<float3> g_texDiffuse : TEX_DIFFUSE0;
+Texture2D<float3> g_texNormal : TEX_NORMAL;
+Texture2D<float> g_texSpec : TEX_SPEC;
+Texture2D<float3> g_texDeepScatterColor : TEX_DEEP_SCATTER_COLOR;
+
+
+
+void SkinMegashader(
+ in Vertex i_vtx,
+ in float3 i_vecCamera,
+ in float4 i_uvzwShadow,
+ out float3 o_rgbLit,
+ uniform bool useSSS,
+ uniform bool useDeepScatter)
+{
+ float2 uv = i_vtx.m_uv;
+
+ // Sample textures
+
+ float3 rgbDiffuse = g_texDiffuse.Sample(g_ssTrilinearRepeatAniso, uv);
+ float3 normalTangent = UnpackNormal(g_texNormal.Sample(g_ssTrilinearRepeatAniso, uv),
+ g_normalStrength);
+ float specReflectance = g_texSpec.Sample(g_ssTrilinearRepeatAniso, uv);
+
+ float3 normalTangentBlurred;
+ if (useSSS || useDeepScatter)
+ {
+ // Sample normal map with level clamped based on blur, to get normal for SSS
+ float level = GFSDK_FaceWorks_CalculateMipLevelForBlurredNormal(
+ g_faceworksData, g_texNormal, g_ssTrilinearRepeatAniso, uv);
+ normalTangentBlurred = UnpackNormal(
+ g_texNormal.SampleLevel(g_ssTrilinearRepeatAniso, uv, level),
+ g_normalStrength);
+ }
+
+ float3 rgbDeepScatter;
+ if (useDeepScatter)
+ {
+ rgbDeepScatter = g_texDeepScatterColor.Sample(g_ssTrilinearRepeatAniso, uv);
+ }
+
+ LightingMegashader(
+ i_vtx,
+ i_vecCamera,
+ i_uvzwShadow,
+ rgbDiffuse,
+ normalTangent,
+ normalTangentBlurred,
+ specReflectance,
+ g_gloss,
+ rgbDeepScatter,
+ g_faceworksData,
+ o_rgbLit,
+ true, // useNormalMap
+ useSSS,
+ useDeepScatter);
+}
+
+#endif // SKIN_HLSLI
diff --git a/samples/d3d11/shaders/skybox_ps.hlsl b/samples/d3d11/shaders/skybox_ps.hlsl
new file mode 100644
index 0000000..9a68f25
--- /dev/null
+++ b/samples/d3d11/shaders/skybox_ps.hlsl
@@ -0,0 +1,43 @@
+//----------------------------------------------------------------------------------
+// File: FaceWorks/samples/sample_d3d11/shaders/skybox_ps.hlsl
+// 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.
+//
+//----------------------------------------------------------------------------------
+
+#include "common.hlsli"
+#include "tonemap.hlsli"
+
+TextureCube<float3> g_texSkybox : TEX_SOURCE;
+
+float3 main(in float3 i_vecView : VIEW) : SV_Target
+{
+ return Tonemap(g_texSkybox.Sample(g_ssTrilinearRepeat, i_vecView));
+}
diff --git a/samples/d3d11/shaders/skybox_vs.hlsl b/samples/d3d11/shaders/skybox_vs.hlsl
new file mode 100644
index 0000000..77c3cec
--- /dev/null
+++ b/samples/d3d11/shaders/skybox_vs.hlsl
@@ -0,0 +1,52 @@
+//----------------------------------------------------------------------------------
+// File: FaceWorks/samples/sample_d3d11/shaders/skybox_vs.hlsl
+// 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.
+//
+//----------------------------------------------------------------------------------
+
+#include "common.hlsli"
+
+cbuffer cbShader : CB_SHADER
+{
+ float4x4 g_matClipToWorldAxes;
+}
+
+void main(
+ in Vertex i_vtx,
+ out float3 o_vecView : VIEW,
+ out float4 o_posClip : SV_Position)
+{
+ // Set z = 1 to draw skybox at the back of the depth range
+ o_posClip = float4(i_vtx.m_pos.xy, 1.0, 1.0);
+
+ float4 vecView = mul(o_posClip, g_matClipToWorldAxes);
+ o_vecView = vecView.xyz / vecView.w;
+}
diff --git a/samples/d3d11/shaders/tess.hlsli b/samples/d3d11/shaders/tess.hlsli
new file mode 100644
index 0000000..718a43b
--- /dev/null
+++ b/samples/d3d11/shaders/tess.hlsli
@@ -0,0 +1,46 @@
+//----------------------------------------------------------------------------------
+// File: FaceWorks/samples/sample_d3d11/shaders/tess.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 TESS_HLSLI
+#define TESS_HLSLI
+
+struct PatchConstData
+{
+ float m_tessFactor[3] : SV_TessFactor;
+ float m_insideTessFactor : SV_InsideTessFactor;
+};
+
+static const float s_tessFactorMax = 3.0;
+
+#endif // TESS_HLSLI
diff --git a/samples/d3d11/shaders/tess_ds.hlsl b/samples/d3d11/shaders/tess_ds.hlsl
new file mode 100644
index 0000000..800a3b6
--- /dev/null
+++ b/samples/d3d11/shaders/tess_ds.hlsl
@@ -0,0 +1,75 @@
+//----------------------------------------------------------------------------------
+// File: FaceWorks/samples/sample_d3d11/shaders/tess_ds.hlsl
+// 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.
+//
+//----------------------------------------------------------------------------------
+
+#include "common.hlsli"
+#include "tess.hlsli"
+
+[domain("tri")]
+void main(
+ in OutputPatch<Vertex, 3> i_cps,
+ in PatchConstData i_pcd,
+ in float3 i_bary : SV_DomainLocation,
+ out Vertex o_vtx,
+ out float3 o_vecCamera : CAMERA,
+ out float4 o_uvzwShadow : UVZW_SHADOW,
+ out float4 o_posClip : SV_Position)
+{
+ // Lerp all attributes but position
+ o_vtx.m_normal = i_bary.x * i_cps[0].m_normal + i_bary.y * i_cps[1].m_normal + i_bary.z * i_cps[2].m_normal;
+ o_vtx.m_uv = i_bary.x * i_cps[0].m_uv + i_bary.y * i_cps[1].m_uv + i_bary.z * i_cps[2].m_uv;
+ o_vtx.m_tangent = i_bary.x * i_cps[0].m_tangent + i_bary.y * i_cps[1].m_tangent + i_bary.z * i_cps[2].m_tangent;
+ o_vtx.m_curvature = i_bary.x * i_cps[0].m_curvature + i_bary.y * i_cps[1].m_curvature + i_bary.z * i_cps[2].m_curvature;
+
+ // Calculate output position using Phong tessellation
+ // (http://perso.telecom-paristech.fr/~boubek/papers/PhongTessellation/)
+
+ // Compute lerped position
+ float3 posVtx = i_bary.x * i_cps[0].m_pos + i_bary.y * i_cps[1].m_pos + i_bary.z * i_cps[2].m_pos;
+
+ // Calculate deltas to project onto three tangent planes
+ float3 vecProj0 = dot(i_cps[0].m_pos - posVtx, i_cps[0].m_normal) * i_cps[0].m_normal;
+ float3 vecProj1 = dot(i_cps[1].m_pos - posVtx, i_cps[1].m_normal) * i_cps[1].m_normal;
+ float3 vecProj2 = dot(i_cps[2].m_pos - posVtx, i_cps[2].m_normal) * i_cps[2].m_normal;
+
+ // Lerp between projection vectors
+ float3 vecOffset = i_bary.x * vecProj0 + i_bary.y * vecProj1 + i_bary.z * vecProj2;
+
+ // Add a fraction of the offset vector to the lerped position
+ posVtx += 0.5 * vecOffset;
+
+ o_vtx.m_pos = posVtx;
+ o_vecCamera = g_posCamera - posVtx;
+ o_uvzwShadow = mul(float4(posVtx, 1.0), g_matWorldToUvzwShadow);
+ o_posClip = mul(float4(posVtx, 1.0), g_matWorldToClip);
+}
diff --git a/samples/d3d11/shaders/tess_hs.hlsl b/samples/d3d11/shaders/tess_hs.hlsl
new file mode 100644
index 0000000..630ea60
--- /dev/null
+++ b/samples/d3d11/shaders/tess_hs.hlsl
@@ -0,0 +1,124 @@
+//----------------------------------------------------------------------------------
+// File: FaceWorks/samples/sample_d3d11/shaders/tess_hs.hlsl
+// 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.
+//
+//----------------------------------------------------------------------------------
+
+#include "common.hlsli"
+#include "tess.hlsli"
+
+void calcHSConstants(
+ in InputPatch<Vertex, 3> i_cps,
+ out PatchConstData o_pcd)
+{
+ // Backface culling: check if the camera is behind all three tangent planes
+ float3 vecNdotV =
+ {
+ dot(g_posCamera - i_cps[0].m_pos, i_cps[0].m_normal),
+ dot(g_posCamera - i_cps[1].m_pos, i_cps[1].m_normal),
+ dot(g_posCamera - i_cps[2].m_pos, i_cps[2].m_normal),
+ };
+ if (all(vecNdotV < 0.0))
+ {
+ o_pcd.m_tessFactor[0] = 0.0;
+ o_pcd.m_tessFactor[1] = 0.0;
+ o_pcd.m_tessFactor[2] = 0.0;
+ o_pcd.m_insideTessFactor = 0.0;
+ return;
+ }
+
+ // Frustum culling: check if all three verts are out on the same side of the frustum
+ // This isn't quite correct because the displacement could make a patch visible even if
+ // it fails this test; but in practice this is nearly impossible to notice
+ float4 posClip0 = mul(float4(i_cps[0].m_pos, 1.0), g_matWorldToClip);
+ float4 posClip1 = mul(float4(i_cps[1].m_pos, 1.0), g_matWorldToClip);
+ float4 posClip2 = mul(float4(i_cps[2].m_pos, 1.0), g_matWorldToClip);
+ float3 xs = { posClip0.x, posClip1.x, posClip2.x };
+ float3 ys = { posClip0.y, posClip1.y, posClip2.y };
+ float3 ws = { posClip0.w, posClip1.w, posClip2.w };
+ if (all(xs < -ws) || all(xs > ws) || all(ys < -ws) || all(ys > ws))
+ {
+ o_pcd.m_tessFactor[0] = 0.0;
+ o_pcd.m_tessFactor[1] = 0.0;
+ o_pcd.m_tessFactor[2] = 0.0;
+ o_pcd.m_insideTessFactor = 0.0;
+ return;
+ }
+
+ // Adaptive tessellation based on a screen-space error estimate using curvature
+
+ // Calculate approximate screen-space edge length, but including z length as well,
+ // so we don't undertessellate edges that are foreshortened
+ float edge0 = length(i_cps[2].m_pos - i_cps[1].m_pos) / (0.5 * (posClip2.w + posClip1.w));
+ float edge1 = length(i_cps[0].m_pos - i_cps[2].m_pos) / (0.5 * (posClip0.w + posClip2.w));
+ float edge2 = length(i_cps[1].m_pos - i_cps[0].m_pos) / (0.5 * (posClip1.w + posClip0.w));
+
+ // Calculate dots of the two normals on each edge - used to give more tessellation
+ // in areas with higher curvature
+ float normalDot0 = dot(i_cps[2].m_normal, i_cps[1].m_normal);
+ float normalDot1 = dot(i_cps[0].m_normal, i_cps[2].m_normal);
+ float normalDot2 = dot(i_cps[1].m_normal, i_cps[0].m_normal);
+
+ // Calculate target screen-space error
+ static const float errPxTarget = 0.5;
+ static const float tanHalfFov = tan(0.5 * 0.5);
+ static const float errTarget = errPxTarget * 2.0 * tanHalfFov / 1080.0;
+
+ // Calculate tess factors using curve fitting approximation to screen-space error
+ // derived from curvature and edge length
+ static const float tessScale = 0.41 / sqrt(errTarget);
+ o_pcd.m_tessFactor[0] = g_tessScale * sqrt(edge0) * pow(1.0 - saturate(normalDot0), 0.27);
+ o_pcd.m_tessFactor[1] = g_tessScale * sqrt(edge1) * pow(1.0 - saturate(normalDot1), 0.27);
+ o_pcd.m_tessFactor[2] = g_tessScale * sqrt(edge2) * pow(1.0 - saturate(normalDot2), 0.27);
+
+ // Clamp to supported range
+ o_pcd.m_tessFactor[0] = clamp(o_pcd.m_tessFactor[0], 1.0, s_tessFactorMax);
+ o_pcd.m_tessFactor[1] = clamp(o_pcd.m_tessFactor[1], 1.0, s_tessFactorMax);
+ o_pcd.m_tessFactor[2] = clamp(o_pcd.m_tessFactor[2], 1.0, s_tessFactorMax);
+
+ // Set interior tess factor to maximum of edge factors
+ o_pcd.m_insideTessFactor = max(max(o_pcd.m_tessFactor[0],
+ o_pcd.m_tessFactor[1]),
+ o_pcd.m_tessFactor[2]);
+}
+
+[domain("tri")]
+[maxtessfactor(s_tessFactorMax)]
+[outputcontrolpoints(3)]
+[outputtopology("triangle_cw")]
+[partitioning("fractional_odd")]
+[patchconstantfunc("calcHSConstants")]
+Vertex main(
+ in InputPatch<Vertex, 3> i_cps,
+ in uint iCp : SV_OutputControlPointID)
+{
+ return i_cps[iCp];
+}
diff --git a/samples/d3d11/shaders/tess_vs.hlsl b/samples/d3d11/shaders/tess_vs.hlsl
new file mode 100644
index 0000000..6d9818c
--- /dev/null
+++ b/samples/d3d11/shaders/tess_vs.hlsl
@@ -0,0 +1,43 @@
+//----------------------------------------------------------------------------------
+// File: FaceWorks/samples/sample_d3d11/shaders/tess_vs.hlsl
+// 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.
+//
+//----------------------------------------------------------------------------------
+
+#include "common.hlsli"
+#include "tess.hlsli"
+
+void main(
+ in Vertex i_vtx,
+ out Vertex o_vtx)
+{
+ o_vtx = i_vtx;
+}
diff --git a/samples/d3d11/shaders/thickness_ps.hlsl b/samples/d3d11/shaders/thickness_ps.hlsl
new file mode 100644
index 0000000..9db96b4
--- /dev/null
+++ b/samples/d3d11/shaders/thickness_ps.hlsl
@@ -0,0 +1,62 @@
+//----------------------------------------------------------------------------------
+// File: FaceWorks/samples/sample_d3d11/shaders/thickness_ps.hlsl
+// 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.
+//
+//----------------------------------------------------------------------------------
+
+#include "common.hlsli"
+#include "GFSDK_FaceWorks.hlsli"
+
+cbuffer cbShader : CB_SHADER
+{
+ GFSDK_FaceWorks_CBData g_faceworksData;
+}
+
+void main(
+ in Vertex i_vtx,
+ in float3 i_vecCamera : CAMERA,
+ in float4 i_uvzwShadow : UVZW_SHADOW,
+ out float4 o_rgba : SV_Target)
+{
+ float3 normalGeom = normalize(i_vtx.m_normal);
+ float3 uvzShadow = i_uvzwShadow.xyz / i_uvzwShadow.w;
+
+ // Apply normal offset to avoid silhouette edge artifacts
+ // !!!UNDONE: move this to vertex shader
+ float3 normalShadow = mul(normalGeom, g_matWorldToUvzShadowNormal);
+ uvzShadow += normalShadow * g_deepScatterNormalOffset;
+
+ float thickness = GFSDK_FaceWorks_EstimateThicknessFromParallelShadowPoisson32(
+ g_faceworksData,
+ g_texShadowMap, g_ssBilinearClamp, uvzShadow);
+
+ o_rgba = float4(thickness.xxx * 0.05, 1.0);
+}
diff --git a/samples/d3d11/shaders/tonemap.hlsli b/samples/d3d11/shaders/tonemap.hlsli
new file mode 100644
index 0000000..f6e8355
--- /dev/null
+++ b/samples/d3d11/shaders/tonemap.hlsli
@@ -0,0 +1,62 @@
+//----------------------------------------------------------------------------------
+// File: FaceWorks/samples/sample_d3d11/shaders/tonemap.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 TONEMAP_HLSLI
+#define TONEMAP_HLSLI
+
+#include "common.hlsli"
+
+float3 Tonemap(float3 rgb)
+{
+ // Apply exposure
+ rgb *= g_exposure;
+
+ // Apply the magic Jim Hejl tonemapping curve (see:
+ // http://www.slideshare.net/ozlael/hable-john-uncharted2-hdr-lighting, slide #140)
+ static const bool useTonemapping = true;
+ if (useTonemapping)
+ {
+ rgb = max(0, rgb - 0.004);
+ rgb = (rgb * (6.2 * rgb + 0.5)) / (rgb * (6.2 * rgb + 1.7) + 0.06);
+ }
+ else
+ {
+ // Just convert to SRGB gamma space
+ rgb = (rgb < 0.0031308) ? (12.92 * rgb) : (1.055 * pow(rgb, 1.0/2.4) - 0.055);
+ }
+
+ return rgb;
+}
+
+#endif // TONEMAP_HLSLI
diff --git a/samples/d3d11/shaders/world_vs.hlsl b/samples/d3d11/shaders/world_vs.hlsl
new file mode 100644
index 0000000..02eb768
--- /dev/null
+++ b/samples/d3d11/shaders/world_vs.hlsl
@@ -0,0 +1,48 @@
+//----------------------------------------------------------------------------------
+// File: FaceWorks/samples/sample_d3d11/shaders/world_vs.hlsl
+// 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.
+//
+//----------------------------------------------------------------------------------
+
+#include "common.hlsli"
+
+void main(
+ in Vertex i_vtx,
+ out Vertex o_vtx,
+ out float3 o_vecCamera : CAMERA,
+ out float4 o_uvzwShadow : UVZW_SHADOW,
+ out float4 o_posClip : SV_Position)
+{
+ o_vtx = i_vtx;
+ o_vecCamera = g_posCamera - i_vtx.m_pos;
+ o_uvzwShadow = mul(float4(i_vtx.m_pos, 1.0), g_matWorldToUvzwShadow);
+ o_posClip = mul(float4(i_vtx.m_pos, 1.0), g_matWorldToClip);
+}
diff --git a/samples/d3d11/util.cpp b/samples/d3d11/util.cpp
new file mode 100644
index 0000000..3681c00
--- /dev/null
+++ b/samples/d3d11/util.cpp
@@ -0,0 +1,1451 @@
+//----------------------------------------------------------------------------------
+// File: FaceWorks/samples/sample_d3d11/util.cpp
+// 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.
+//
+//----------------------------------------------------------------------------------
+
+#include "util.h"
+#include "shader.h"
+
+#include <algorithm>
+
+#include <DirectXMath.h>
+
+#include <DXUT/Core/DXUT.h>
+#include <DXUT/Core/DXUTmisc.h>
+#include <DXUT/Core/WICTextureLoader.h>
+#include <DXUT/Core/DDSTextureLoader.h>
+
+#include <GFSDK_FaceWorks.h>
+
+#if defined(_MSC_VER) && (_MSC_VER < 1900)
+#pragma warning(disable: 4351) // Before VS2015 the warning "New behavior: array elements will be default-initialized" is produced when an array is construct-initialized with ().
+#endif
+
+using namespace std;
+using namespace DirectX;
+
+static wstring StrVprintf(const wchar_t * fmt, va_list args)
+{
+ int cChAlloc = _vscwprintf(fmt, args) + 1;
+ wstring result = wstring(cChAlloc, L'\0');
+ _vsnwprintf_s(&result[0], cChAlloc, _TRUNCATE, fmt, args);
+ return result;
+}
+
+wstring StrPrintf(const wchar_t * fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ return StrVprintf(fmt, args);
+}
+
+#if defined(_DEBUG)
+void DebugPrintf(const wchar_t * fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ OutputDebugString(StrVprintf(fmt, args).c_str());
+}
+#else
+void DebugPrintf(const wchar_t * /*fmt*/, ...) {}
+#endif
+
+HRESULT LoadFile(const wchar_t * strFilename, vector<char> * pData, bool bText)
+{
+ FILE * pFile = nullptr;
+ if (_wfopen_s(&pFile, strFilename, bText ? L"rt" : L"rb") != 0 || !pFile)
+ return E_FAIL;
+ assert(pFile);
+
+ // Determine file size
+ fseek(pFile, 0, SEEK_END);
+ size_t size = ftell(pFile);
+
+ // Read the whole file into memory
+ assert(pData);
+ pData->resize(bText ? size+1 : size);
+ rewind(pFile);
+ size_t sizeRead = fread(&(*pData)[0], sizeof(char), size, pFile);
+
+ // Size can be smaller for text files, due to newline conversion
+ assert(sizeRead == size || (bText && sizeRead < size));
+ fclose(pFile);
+
+ // Automatically null-terminate text files so string functions can be used
+ if (bText)
+ {
+ pData->resize(sizeRead + 1);
+ (*pData)[sizeRead] = 0;
+ }
+
+ return S_OK;
+}
+
+
+
+const wchar_t * BaseFilename(const wchar_t * strFilename)
+{
+ if (const wchar_t * strBase = wcsrchr(strFilename, L'\\'))
+ return strBase + 1;
+ else
+ return strFilename;
+}
+
+#if defined(_DEBUG)
+void SetDebugName(ID3D11DeviceChild * pD3DObject, const char * strName)
+{
+ HRESULT hr = pD3DObject->SetPrivateData(WKPDID_D3DDebugObjectName, UINT(strlen(strName)), strName);
+ assert(SUCCEEDED(hr));
+}
+
+void SetDebugName(ID3D11DeviceChild * pD3DObject, const wchar_t * strName)
+{
+ // D3D only supports narrow strings for debug names; convert to UTF-8
+ int cCh = WideCharToMultiByte(CP_UTF8, 0, strName, -1, nullptr, 0, nullptr, nullptr);
+ string strUTF8(cCh, 0);
+ WideCharToMultiByte(CP_UTF8, 0, strName, -1, &strUTF8[0], cCh, nullptr, nullptr);
+ HRESULT hr = pD3DObject->SetPrivateData(WKPDID_D3DDebugObjectName, cCh, strUTF8.c_str());
+ assert(SUCCEEDED(hr));
+}
+#else
+void SetDebugName(ID3D11DeviceChild * /*pD3DObject*/, const char * /*strName*/) {}
+void SetDebugName(ID3D11DeviceChild * /*pD3DObject*/, const wchar_t * /*strName*/) {}
+#endif
+
+// CMesh implementation
+
+CMesh::CMesh()
+: m_verts(),
+ m_indices(),
+ m_pVtxBuffer(nullptr),
+ m_pIdxBuffer(nullptr),
+ m_vtxStride(0),
+ m_cIdx(0),
+ m_primtopo(D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED),
+ m_posMin(0.0f, 0.0f, 0.0f),
+ m_posMax(0.0f, 0.0f, 0.0f),
+ m_posCenter(0.0f, 0.0f, 0.0f),
+ m_diameter(0.0f),
+ m_uvScale(1.0f)
+{
+}
+
+void CMesh::Draw(ID3D11DeviceContext * pCtx)
+{
+ UINT zero = 0;
+ pCtx->IASetVertexBuffers(0, 1, &m_pVtxBuffer, &m_vtxStride, &zero);
+ pCtx->IASetIndexBuffer(m_pIdxBuffer, DXGI_FORMAT_R32_UINT, 0);
+ pCtx->DrawIndexed(m_cIdx, 0, 0);
+}
+
+void CMesh::Release()
+{
+ m_verts.clear();
+ m_indices.clear();
+ SAFE_RELEASE(m_pVtxBuffer);
+ SAFE_RELEASE(m_pIdxBuffer);
+}
+
+HRESULT CreateFullscreenMesh(ID3D11Device * pDevice, CMesh * pMesh)
+{
+ HRESULT hr;
+
+ // Positions are directly in clip space; normals aren't used.
+
+ Vertex verts[] =
+ {
+ // pos normal uv
+ { XMFLOAT3(-1, -1, 0), XMFLOAT3(), XMFLOAT2(0, 1) },
+ { XMFLOAT3( 3, -1, 0), XMFLOAT3(), XMFLOAT2(2, 1) },
+ { XMFLOAT3(-1, 3, 0), XMFLOAT3(), XMFLOAT2(0, -1) },
+ };
+
+ UINT indices[] = { 0, 1, 2 };
+
+ pMesh->m_verts.assign(&verts[0], &verts[dim(verts)]);
+ pMesh->m_indices.assign(&indices[0], &indices[dim(indices)]);
+
+ D3D11_BUFFER_DESC vtxBufferDesc =
+ {
+ sizeof(Vertex) * dim(verts),
+ D3D11_USAGE_IMMUTABLE,
+ D3D11_BIND_VERTEX_BUFFER,
+ 0, // no cpu access
+ 0, // no misc flags
+ 0, // structured buffer stride
+ };
+ D3D11_SUBRESOURCE_DATA vtxBufferData = { &verts[0], 0, 0 };
+
+ V_RETURN(pDevice->CreateBuffer(&vtxBufferDesc, &vtxBufferData, &pMesh->m_pVtxBuffer));
+
+ D3D11_BUFFER_DESC idxBufferDesc =
+ {
+ sizeof(UINT) * dim(indices),
+ D3D11_USAGE_IMMUTABLE,
+ D3D11_BIND_INDEX_BUFFER,
+ 0, // no cpu access
+ 0, // no misc flags
+ 0, // structured buffer stride
+ };
+ D3D11_SUBRESOURCE_DATA idxBufferData = { &indices[0], 0, 0 };
+
+ V_RETURN(pDevice->CreateBuffer(&idxBufferDesc, &idxBufferData, &pMesh->m_pIdxBuffer));
+
+ pMesh->m_vtxStride = sizeof(Vertex);
+ pMesh->m_cIdx = UINT(dim(indices));
+ pMesh->m_primtopo = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
+
+ SetDebugName(pMesh->m_pVtxBuffer, "Fullscreen mesh VB");
+ SetDebugName(pMesh->m_pIdxBuffer, "Fullscreen mesh IB");
+
+ return S_OK;
+}
+
+
+
+// Mesh loading - helper functions
+
+HRESULT LoadObjMeshRaw(
+ const wchar_t * strFilename,
+ vector<Vertex> * pVerts,
+ vector<int> * pIndices,
+ XMFLOAT3 * pPosMin,
+ XMFLOAT3 * pPosMax)
+{
+ HRESULT hr;
+
+ // Read the whole file into memory
+ vector<char> data;
+ V_RETURN(LoadFile(strFilename, &data, true));
+
+ vector<XMFLOAT3> positions;
+ vector<XMFLOAT3> normals;
+ vector<XMFLOAT2> uvs;
+
+ struct OBJVertex { int iPos, iNormal, iUv; };
+ vector<OBJVertex> OBJverts;
+
+ struct OBJFace { int iVertStart, iVertEnd; };
+ vector<OBJFace> OBJfaces;
+
+
+ XMVECTOR posMin = XMVectorReplicate(FLT_MAX);
+ XMVECTOR posMax = XMVectorReplicate(-FLT_MAX);
+
+ // Parse the OBJ format line-by-line
+ char * pCtxLine = nullptr;
+ for (char * pLine = strtok_s(&data[0], "\n", &pCtxLine);
+ pLine;
+ pLine = strtok_s(nullptr, "\n", &pCtxLine))
+ {
+ // Strip comments starting with #
+ if (char * pChzComment = strchr(pLine, '#'))
+ *pChzComment = 0;
+
+ // Parse the line token-by-token
+ char * pCtxToken = nullptr;
+ char * pToken = strtok_s(pLine, " \t", &pCtxToken);
+
+ // Ignore blank lines
+ if (!pToken)
+ continue;
+
+ if (_stricmp(pToken, "v") == 0)
+ {
+
+ XMFLOAT3 pos;
+ pos.x = float(atof(strtok_s(nullptr, " \t", &pCtxToken)));
+ pos.y = float(atof(strtok_s(nullptr, " \t", &pCtxToken)));
+ pos.z = float(atof(strtok_s(nullptr, " \t", &pCtxToken)));
+ positions.push_back(pos);
+
+ XMVECTOR pos4 = XMLoadFloat3(&pos);
+
+ posMin = XMVectorMin(posMin, pos4);
+ posMax = XMVectorMax(posMax, pos4);
+ }
+ else if (_stricmp(pToken, "vn") == 0)
+ {
+ // Add normal
+ XMFLOAT3 normal;
+ normal.x = float(atof(strtok_s(nullptr, " \t", &pCtxToken)));
+ normal.y = float(atof(strtok_s(nullptr, " \t", &pCtxToken)));
+ normal.z = float(atof(strtok_s(nullptr, " \t", &pCtxToken)));
+ normals.push_back(normal);
+ }
+ else if (_stricmp(pToken, "vt") == 0)
+ {
+ // Add UV, flipping V-axis since OBJ is stored in the opposite convention
+ XMFLOAT2 uv;
+ uv.x = float(atof(strtok_s(nullptr, " \t", &pCtxToken)));
+ uv.y = 1.0f - float(atof(strtok_s(nullptr, " \t", &pCtxToken)));
+ uvs.push_back(uv);
+ }
+ else if (_stricmp(pToken, "f") == 0)
+ {
+ // Add face
+ OBJFace face;
+ face.iVertStart = int(OBJverts.size());
+
+ while (char * pToken2 = strtok_s(nullptr, " \t", &pCtxToken))
+ {
+ // Parse vertex specification, with slashes separating position, UV, normal indices
+ // Note: assuming all three components are present, OBJ format allows some to be missing.
+ OBJVertex vert;
+ sscanf_s(pToken2, "%d/%d/%d", &vert.iPos, &vert.iUv, &vert.iNormal);
+
+ // OBJ format uses 1-based indices; correct them
+ --vert.iPos;
+ --vert.iNormal;
+ --vert.iUv;
+
+ OBJverts.push_back(vert);
+ }
+
+ face.iVertEnd = int(OBJverts.size());
+ OBJfaces.push_back(face);
+ }
+ else
+ {
+ // Unknown command; just ignore
+ }
+ }
+
+ // Convert to vertex buffer and index buffer
+
+ pVerts->reserve(OBJverts.size());
+
+ for (size_t iVert = 0, cVert = OBJverts.size(); iVert < cVert; ++iVert)
+ {
+ OBJVertex objv = OBJverts[iVert];
+ Vertex v = {};
+ v.m_pos = positions[objv.iPos];
+ v.m_normal = normals[objv.iNormal];
+ v.m_uv = uvs[objv.iUv];
+ pVerts->push_back(v);
+ }
+
+ for (size_t iFace = 0, cFace = OBJfaces.size(); iFace < cFace; ++iFace)
+ {
+ OBJFace face = OBJfaces[iFace];
+
+ int iVertBase = face.iVertStart;
+
+ // Triangulate the face
+ for (int iVert = face.iVertStart + 2; iVert < face.iVertEnd; ++iVert)
+ {
+ pIndices->push_back(iVertBase);
+ pIndices->push_back(iVert - 1);
+ pIndices->push_back(iVert);
+ }
+ }
+
+ if (pPosMin) XMStoreFloat3(pPosMin, posMin);
+ if (pPosMax) XMStoreFloat3(pPosMax, posMax);
+
+ return S_OK;
+}
+
+void DeduplicateVerts(CMesh * pMesh)
+{
+ struct VertexHasher
+ {
+ hash<float> fh;
+ size_t operator () (const Vertex & v) const
+ {
+ return fh(v.m_pos.x) ^ fh(v.m_pos.y) ^ fh(v.m_pos.z) ^
+ fh(v.m_normal.x) ^ fh(v.m_normal.y) ^ fh(v.m_normal.z) ^
+ fh(v.m_uv.x) ^ fh(v.m_uv.y) ^
+ fh(v.m_curvature);
+ }
+ };
+
+ struct VertexEquator
+ {
+ bool operator () (const Vertex & u, const Vertex & v) const
+ {
+ return (u.m_pos.x == v.m_pos.x &&
+ u.m_pos.y == v.m_pos.y &&
+ u.m_pos.z == v.m_pos.z &&
+ u.m_normal.x == v.m_normal.x &&
+ u.m_normal.y == v.m_normal.y &&
+ u.m_normal.z == v.m_normal.z &&
+ u.m_uv.x == v.m_uv.x &&
+ u.m_uv.y == v.m_uv.y &&
+ u.m_curvature == v.m_curvature);
+ }
+ };
+
+ vector<Vertex> vertsDeduplicated;
+ vector<int> remappingTable;
+ unordered_map<Vertex, int, VertexHasher, VertexEquator> mapVertToIndex;
+
+ vertsDeduplicated.reserve(pMesh->m_verts.size());
+ remappingTable.reserve(pMesh->m_verts.size());
+
+ for (int i = 0, cVert = int(pMesh->m_verts.size()); i < cVert; ++i)
+ {
+ const Vertex & vert = pMesh->m_verts[i];
+ unordered_map<Vertex, int, VertexHasher, VertexEquator>::iterator
+ iter = mapVertToIndex.find(vert);
+ if (iter == mapVertToIndex.end())
+ {
+ // Found a new vertex that's not in the map yet.
+ int newIndex = int(vertsDeduplicated.size());
+ vertsDeduplicated.push_back(vert);
+ remappingTable.push_back(newIndex);
+ mapVertToIndex[vert] = newIndex;
+ }
+ else
+ {
+ // It's already in the map; re-use the previous index
+ int newIndex = iter->second;
+ remappingTable.push_back(newIndex);
+ }
+ }
+
+ assert(vertsDeduplicated.size() <= pMesh->m_verts.size());
+ assert(remappingTable.size() == pMesh->m_verts.size());
+
+ vector<int> indicesRemapped;
+ indicesRemapped.reserve(pMesh->m_indices.size());
+
+ for (int i = 0, cIndex = int(pMesh->m_indices.size()); i < cIndex; ++i)
+ {
+ indicesRemapped.push_back(remappingTable[pMesh->m_indices[i]]);
+ }
+
+ pMesh->m_verts.swap(vertsDeduplicated);
+ pMesh->m_indices.swap(indicesRemapped);
+}
+
+// Custom allocator for FaceWorks - just logs the allocs and passes through to CRT
+
+void * MallocForFaceWorks(size_t bytes)
+{
+ void * p = ::operator new(bytes);
+ DebugPrintf(L"FaceWorks alloced %d bytes: %p\n", bytes, p);
+ return p;
+}
+
+void FreeForFaceWorks(void * p)
+{
+ DebugPrintf(L"FaceWorks freed %p\n", p);
+ ::operator delete(p);
+}
+
+void CalculateCurvature(CMesh * pMesh)
+{
+ // Calculate mesh curvature - also demonstrate using a custom allocator
+
+ GFSDK_FaceWorks_ErrorBlob errorBlob = {};
+ gfsdk_new_delete_t allocator = { &MallocForFaceWorks, &FreeForFaceWorks };
+ GFSDK_FaceWorks_Result result = GFSDK_FaceWorks_CalculateMeshCurvature(
+ int(pMesh->m_verts.size()),
+ &pMesh->m_verts[0].m_pos,
+ sizeof(Vertex),
+ &pMesh->m_verts[0].m_normal,
+ sizeof(Vertex),
+ int(pMesh->m_indices.size()),
+ &pMesh->m_indices[0],
+ 2, // smoothing passes
+ &pMesh->m_verts[0].m_curvature,
+ sizeof(Vertex),
+ &errorBlob,
+ &allocator);
+
+ if (result != GFSDK_FaceWorks_OK)
+ {
+#if defined(_DEBUG)
+ wchar_t msg[512];
+ _snwprintf_s(msg, dim(msg), _TRUNCATE,
+ L"GFSDK_FaceWorks_CalculateMeshCurvature() failed:\n%hs", errorBlob.m_msg);
+ DXUTTrace(__FILE__, __LINE__, E_FAIL, msg, true);
+#endif
+ GFSDK_FaceWorks_FreeErrorBlob(&errorBlob);
+ return;
+ }
+
+#if defined(_DEBUG) && 0
+ // Report min, max, mean curvature over mesh
+ float minCurvature = FLT_MAX;
+ float maxCurvature = -FLT_MAX;
+ float curvatureSum = 0.0f;
+ for (int i = 0, cVert = int(pMesh->m_verts.size()); i < cVert; ++i)
+ {
+ minCurvature = min(minCurvature, pMesh->m_verts[i].m_curvature);
+ maxCurvature = max(maxCurvature, pMesh->m_verts[i].m_curvature);
+ curvatureSum += pMesh->m_verts[i].m_curvature;
+ }
+ float meanCurvature = curvatureSum / float(pMesh->m_verts.size());
+ DebugPrintf(
+ L"\tCurvature min = %0.2f cm^-1, max = %0.2f cm^-1, mean = %0.2f cm^-1\n",
+ minCurvature, maxCurvature, meanCurvature);
+#endif // defined(_DEBUG)
+}
+
+void CalculateUVScale(CMesh * pMesh)
+{
+ GFSDK_FaceWorks_ErrorBlob errorBlob = {};
+ GFSDK_FaceWorks_Result result = GFSDK_FaceWorks_CalculateMeshUVScale(
+ int(pMesh->m_verts.size()),
+ &pMesh->m_verts[0].m_pos,
+ sizeof(Vertex),
+ &pMesh->m_verts[0].m_uv,
+ sizeof(Vertex),
+ int(pMesh->m_indices.size()),
+ &pMesh->m_indices[0],
+ &pMesh->m_uvScale,
+ &errorBlob);
+ if (result != GFSDK_FaceWorks_OK)
+ {
+#if defined(_DEBUG)
+ wchar_t msg[512];
+ _snwprintf_s(msg, dim(msg), _TRUNCATE,
+ L"GFSDK_FaceWorks_CalculateMeshUVScale() failed:\n%hs", errorBlob.m_msg);
+ DXUTTrace(__FILE__, __LINE__, E_FAIL, msg, true);
+#endif
+ GFSDK_FaceWorks_FreeErrorBlob(&errorBlob);
+ return;
+ }
+
+#if 0
+ DebugPrintf(L"\tUV scale %0.2f cm\n", pMesh->m_uvScale);
+#endif
+}
+
+void CalculateTangents(CMesh * pMesh)
+{
+ assert(pMesh->m_indices.size() % 3 == 0);
+
+ // Clear tangents to zero
+ for (int i = 0, c = int(pMesh->m_verts.size()); i < c; ++i)
+ {
+ pMesh->m_verts[i].m_tangent = XMFLOAT3(0, 0, 0);
+ }
+
+ // Generate a tangent for each triangle, based on triangle's UV mapping,
+ // and accumulate onto vertex
+ for (int i = 0, c = int(pMesh->m_indices.size()); i < c; i += 3)
+ {
+ int indices[3] = { pMesh->m_indices[i], pMesh->m_indices[i+1], pMesh->m_indices[i+2] };
+
+ // Gather positions for this triangle
+ XMVECTOR facePositions[3] =
+ {
+ XMLoadFloat3(&pMesh->m_verts[indices[0]].m_pos),
+ XMLoadFloat3(&pMesh->m_verts[indices[1]].m_pos),
+ XMLoadFloat3(&pMesh->m_verts[indices[2]].m_pos)
+ };
+
+ // Calculate edge and normal vectors
+ XMVECTOR edge0 = facePositions[1] - facePositions[0];
+ XMVECTOR edge1 = facePositions[2] - facePositions[0];
+ XMVECTOR normal = XMVector3Cross(edge0, edge1);
+
+ // Calculate matrix from unit triangle to position space
+ XMMATRIX matUnitToPosition(edge0, edge1, normal, XMVectorSet(0.0f, 0.0f, 0.0f, 1.0f));
+
+ // Gather UVs for this triangle
+ XMFLOAT2 faceUVs[3] =
+ {
+ pMesh->m_verts[indices[0]].m_uv,
+ pMesh->m_verts[indices[1]].m_uv,
+ pMesh->m_verts[indices[2]].m_uv,
+ };
+
+
+#if 0
+ // This code is no longer used because it caused to invert a rank-deficient matrix
+
+ // Calculate UV space edge vectors
+ // Calculate matrix from unit triangle to UV space
+ XMMATRIX matUnitToUV(
+ faceUVs[1].x - faceUVs[0].x, faceUVs[1].y - faceUVs[0].y, 0.0f, 0.0f,
+ faceUVs[2].x - faceUVs[0].x, faceUVs[2].y - faceUVs[0].y, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f);
+ // Calculate matrix from UV space to position space
+ XMMATRIX matUVToUnit = XMMatrixInverse(nullptr, matUnitToUV);
+ XMMATRIX matUVToPosition = XMMatrixMultiply(matUVToUnit, matUnitToPosition);
+
+ // The x-axis of that matrix is the tangent vector
+ XMVECTOR tangent = XMVector3Normalize(matUVToPosition.r[0]);
+#else
+ XMMATRIX matUVToUnitDenormalized(
+ faceUVs[2].y - faceUVs[0].y, faceUVs[0].y - faceUVs[1].y, 0.0f, 0.0f,
+ faceUVs[0].x - faceUVs[2].x, faceUVs[1].x - faceUVs[0].x, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f
+ );
+ XMMATRIX matUVToPositionDenormalized = XMMatrixMultiply(matUVToUnitDenormalized, matUnitToPosition);
+
+ XMVECTOR tangent = matUVToPositionDenormalized.r[0];
+ if (XMVector3Equal(tangent, XMVectorZero()))
+ {
+ tangent = XMVector2Cross(matUVToPositionDenormalized.r[1], matUVToPositionDenormalized.r[2]);
+ if (XMVector3Equal(tangent, XMVectorZero()))
+ {
+ tangent = edge0;
+ }
+ }
+
+ tangent = XMVector3Normalize(tangent);
+#endif
+ // Accumulate onto vertices
+ XMStoreFloat3(&pMesh->m_verts[indices[0]].m_tangent, XMLoadFloat3(&pMesh->m_verts[indices[0]].m_tangent) + tangent);
+ XMStoreFloat3(&pMesh->m_verts[indices[1]].m_tangent, XMLoadFloat3(&pMesh->m_verts[indices[1]].m_tangent) + tangent);
+ XMStoreFloat3(&pMesh->m_verts[indices[2]].m_tangent, XMLoadFloat3(&pMesh->m_verts[indices[2]].m_tangent) + tangent);
+ }
+
+ // Normalize summed tangents
+ for (int i = 0, c = int(pMesh->m_verts.size()); i < c; ++i)
+ {
+ XMStoreFloat3(&pMesh->m_verts[i].m_tangent, XMVector3Normalize(XMLoadFloat3(&pMesh->m_verts[i].m_tangent)));
+ }
+}
+
+HRESULT LoadObjMesh(
+ const wchar_t * strFilename,
+ ID3D11Device * pDevice,
+ CMesh * pMesh)
+{
+ HRESULT hr;
+
+ V_RETURN(LoadObjMeshRaw(
+ strFilename, &pMesh->m_verts, &pMesh->m_indices,
+ &pMesh->m_posMin, &pMesh->m_posMax));
+
+ DeduplicateVerts(pMesh);
+
+ DebugPrintf(
+ L"Loaded %s, %d verts, %d indices\n",
+ strFilename, int(pMesh->m_verts.size()), int(pMesh->m_indices.size()));
+
+ // !!!UNDONE: vertex cache optimization?
+
+ XMVECTOR posMin = XMLoadFloat3(&pMesh->m_posMin);
+ XMVECTOR posMax = XMLoadFloat3(&pMesh->m_posMax);
+ XMStoreFloat3(&pMesh->m_posCenter, 0.5f * (posMin + posMax));
+ pMesh->m_diameter = XMVectorGetX(XMVector3Length(posMax - posMin));
+
+ CalculateCurvature(pMesh);
+ CalculateUVScale(pMesh);
+ CalculateTangents(pMesh);
+
+ D3D11_BUFFER_DESC vtxBufferDesc =
+ {
+ sizeof(Vertex) * UINT(pMesh->m_verts.size()),
+ D3D11_USAGE_IMMUTABLE,
+ D3D11_BIND_VERTEX_BUFFER,
+ 0, // no cpu access
+ 0, // no misc flags
+ 0, // structured buffer stride
+ };
+ D3D11_SUBRESOURCE_DATA vtxBufferData = { &pMesh->m_verts[0], 0, 0 };
+
+ V_RETURN(pDevice->CreateBuffer(&vtxBufferDesc, &vtxBufferData, &pMesh->m_pVtxBuffer));
+
+ D3D11_BUFFER_DESC idxBufferDesc =
+ {
+ sizeof(int) * UINT(pMesh->m_indices.size()),
+ D3D11_USAGE_IMMUTABLE,
+ D3D11_BIND_INDEX_BUFFER,
+ 0, // no cpu access
+ 0, // no misc flags
+ 0, // structured buffer stride
+ };
+ D3D11_SUBRESOURCE_DATA idxBufferData = { &pMesh->m_indices[0], 0, 0 };
+
+ V_RETURN(pDevice->CreateBuffer(&idxBufferDesc, &idxBufferData, &pMesh->m_pIdxBuffer));
+
+ pMesh->m_vtxStride = sizeof(Vertex);
+ pMesh->m_cIdx = UINT(pMesh->m_indices.size());
+ pMesh->m_primtopo = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
+
+ SetDebugName(pMesh->m_pVtxBuffer, StrPrintf(L"%s VB", BaseFilename(strFilename)).c_str());
+ SetDebugName(pMesh->m_pIdxBuffer, StrPrintf(L"%s IB", BaseFilename(strFilename)).c_str());
+
+ return S_OK;
+}
+
+
+bool WCStringEndsWith(const wchar_t* hay, const wchar_t* needle)
+{
+ size_t hay_lenght = wcslen(hay);
+ size_t needle_length = wcslen(needle);
+ if (hay_lenght < needle_length) return false;
+ return wcscmp(hay + hay_lenght - needle_length, needle) == 0;
+}
+
+HRESULT LoadTexture(
+ const wchar_t * strFilename,
+ ID3D11Device * pDevice,
+ ID3D11ShaderResourceView ** ppSrv,
+ int flags)
+{
+ return LoadTexture(strFilename, pDevice, nullptr, ppSrv, flags);
+}
+
+HRESULT LoadTexture(
+ const wchar_t * strFilename,
+ ID3D11Device * pDevice,
+ ID3D11DeviceContext * pDeviceContext,
+ ID3D11ShaderResourceView ** ppSrv,
+ int flags)
+{
+ HRESULT hr;
+
+ bool bMipmap = (flags & LT_Mipmap) != 0;
+ bool bHDR = (flags & LT_HDR) != 0;
+ bool bCubemap = (flags & LT_Cubemap) != 0;
+ bool bLinear = (flags & LT_Linear) != 0;
+
+ // Load the texture, generating mipmaps if requested
+
+ if (WCStringEndsWith(strFilename, L".dds"))
+ {
+ bMipmap = false;
+ V_RETURN(CreateDDSTextureFromFileEx(
+ pDevice,
+ bMipmap ? pDeviceContext : nullptr,
+ strFilename,
+ 4096,
+ bMipmap ? D3D11_USAGE_DEFAULT : D3D11_USAGE_IMMUTABLE,
+ (D3D11_BIND_SHADER_RESOURCE | (bMipmap ? (D3D11_BIND_RENDER_TARGET) : 0)),
+ 0,
+ (bCubemap ? D3D11_RESOURCE_MISC_TEXTURECUBE : 0) | (bMipmap ? D3D11_RESOURCE_MISC_GENERATE_MIPS : 0),
+ !(bHDR || bLinear),
+ nullptr,
+ ppSrv));
+
+ }
+ else
+ {
+ assert((!bMipmap) || (pDeviceContext != nullptr));
+ V_RETURN(CreateWICTextureFromFileEx(
+ pDevice,
+ bMipmap ? pDeviceContext : nullptr,
+ strFilename,
+ 4096,
+ bMipmap ? D3D11_USAGE_DEFAULT : D3D11_USAGE_IMMUTABLE,
+ (D3D11_BIND_SHADER_RESOURCE | (bMipmap ? (D3D11_BIND_RENDER_TARGET) : 0)),
+ 0,
+ (bCubemap ? D3D11_RESOURCE_MISC_TEXTURECUBE : 0) | (bMipmap ? D3D11_RESOURCE_MISC_GENERATE_MIPS : 0),
+ !(bHDR || bLinear),
+ nullptr,
+ ppSrv));
+ }
+
+#if defined(_DEBUG)
+ // Set the name of the texture
+ SetDebugName(*ppSrv, BaseFilename(strFilename));
+
+ D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
+ (*ppSrv)->GetDesc(&srvDesc);
+
+ UINT cMipLevels = 1;
+ const wchar_t * strDimension = L"other";
+ switch (srvDesc.ViewDimension)
+ {
+ case D3D11_SRV_DIMENSION_TEXTURE2D:
+ strDimension = L"2D";
+ cMipLevels = srvDesc.Texture2D.MipLevels;
+ break;
+
+ case D3D11_SRV_DIMENSION_TEXTURECUBE:
+ strDimension = L"cube";
+ cMipLevels = srvDesc.TextureCube.MipLevels;
+ break;
+
+ default: assert(false); break;
+ }
+
+ DebugPrintf(
+ L"Loaded %s, format %s, %s, %d mip levels\n",
+ strFilename,
+ DXUTDXGIFormatToString(srvDesc.Format, false),
+ strDimension,
+ cMipLevels);
+#endif
+
+ return S_OK;
+}
+
+
+
+// CMayaStyleCamera implementation
+
+CMayaStyleCamera::CMayaStyleCamera()
+: CBaseCamera(),
+ m_fRadius(5.0f)
+{
+}
+
+void CMayaStyleCamera::FrameMove(FLOAT /*fElapsedTime*/)
+{
+ if (IsKeyDown(m_aKeys[CAM_RESET]))
+ Reset();
+
+ // Get the mouse movement (if any) if the mouse button are down
+ GetInput(m_bEnablePositionMovement, m_nCurrentButtonMask != 0, false);
+
+ // If left mouse button is down, update yaw and pitch based on mouse
+ if (m_nCurrentButtonMask & MOUSE_LEFT_BUTTON)
+ {
+ // Update the pitch & yaw angle based on mouse movement
+ float fYawDelta = -m_vMouseDelta.x * m_fRotationScaler;
+ float fPitchDelta = m_vMouseDelta.y * m_fRotationScaler;
+
+ // Invert pitch if requested
+ if (m_bInvertPitch)
+ fPitchDelta = -fPitchDelta;
+
+ m_fCameraPitchAngle += fPitchDelta;
+ m_fCameraYawAngle += fYawDelta;
+
+ // Limit pitch to straight up or straight down
+ m_fCameraPitchAngle = max(-XM_PI / 2.0f, m_fCameraPitchAngle);
+ m_fCameraPitchAngle = min(+XM_PI / 2.0f, m_fCameraPitchAngle);
+ }
+
+ // If mouse wheel is scrolled or right mouse button is down, update radius
+ if (m_nMouseWheelDelta != 0)
+ m_fRadius -= m_nMouseWheelDelta * m_fRadius * 0.1f / 120.0f;
+ if (m_nCurrentButtonMask & MOUSE_RIGHT_BUTTON)
+ m_fRadius += m_vMouseDelta.y * m_fRadius * 0.01f;
+ m_fRadius = max(m_fRadius, 1.0f);
+ m_nMouseWheelDelta = 0;
+
+ // Make a rotation matrix based on the camera's yaw & pitch
+ XMMATRIX mCameraRot = XMMatrixRotationRollPitchYaw(m_fCameraPitchAngle, m_fCameraYawAngle, 0.0f);
+
+ XMVECTOR vRight(mCameraRot.r[0]);
+ XMVECTOR vUp(mCameraRot.r[1]);
+ XMVECTOR vForward(mCameraRot.r[2]);
+
+ XMVECTOR vLookAt = XMLoadFloat3(&m_vLookAt);
+
+ // If middle mouse button is down, update look-at point
+ if (m_nCurrentButtonMask & MOUSE_MIDDLE_BUTTON)
+ {
+ vLookAt += vRight * (m_vMouseDelta.x * m_fRadius * 0.005f);
+ vLookAt += vUp * (m_vMouseDelta.y * m_fRadius * 0.005f);
+ XMStoreFloat3(&m_vLookAt, vLookAt);
+ }
+
+ // Update the eye point based on a radius away from the lookAt position
+ XMVECTOR vEye = vLookAt - vForward * m_fRadius;
+ XMStoreFloat3(&m_vEye, vEye);
+
+ // Update the view matrix
+ XMStoreFloat4x4(&m_mView, XMMatrixLookAtRH(vEye, vLookAt, vUp));
+}
+
+void CMayaStyleCamera::SetProjParams(FLOAT fFOV, FLOAT fAspect, FLOAT fNearPlane, FLOAT fFarPlane)
+{
+ // Set attributes for the projection matrix
+ m_fFOV = fFOV;
+ m_fAspect = fAspect;
+ m_fNearPlane = fNearPlane;
+ m_fFarPlane = fFarPlane;
+
+ XMStoreFloat4x4(&m_mProj, XMMatrixPerspectiveFovRH(fFOV, fAspect, fNearPlane, fFarPlane));
+}
+
+void CMayaStyleCamera::SetViewParams(FXMVECTOR pvEyePt, FXMVECTOR pvLookatPt)
+{
+ CBaseCamera::SetViewParams(pvEyePt, pvLookatPt);
+
+ XMVECTOR vecLook = pvLookatPt - pvEyePt;
+ m_fRadius = XMVectorGetX(XMVector3Length(vecLook));
+}
+
+
+
+// CFirstPersonCameraRH implementation
+
+void CFirstPersonCameraRH::FrameMove(FLOAT fElapsedTime)
+{
+ if (DXUTGetGlobalTimer()->IsStopped())
+ {
+ if (DXUTGetFPS() == 0.0f)
+ fElapsedTime = 0;
+ else
+ fElapsedTime = 1.0f / DXUTGetFPS();
+ }
+
+ if (IsKeyDown(m_aKeys[CAM_RESET]))
+ Reset();
+
+ // Get keyboard/mouse/gamepad input
+ GetInput(m_bEnablePositionMovement, (m_nActiveButtonMask & m_nCurrentButtonMask) || m_bRotateWithoutButtonDown,
+ true);
+
+ // Get amount of velocity based on the keyboard input and drag (if any)
+ UpdateVelocity(fElapsedTime);
+
+ // Simple euler method to calculate position delta
+ XMVECTOR vPosDelta = XMVectorSet(-m_vVelocity.x, m_vVelocity.y, m_vVelocity.z, 0.0f)*fElapsedTime;
+ if (GetAsyncKeyState(VK_LSHIFT) != 0) {
+ vPosDelta *= 2.0f;
+ }
+
+ // If rotating the camera
+ if ((m_nActiveButtonMask & m_nCurrentButtonMask) ||
+ m_bRotateWithoutButtonDown ||
+ m_vGamePadRightThumb.x != 0 ||
+ m_vGamePadRightThumb.z != 0)
+ {
+ // Update the pitch & yaw angle based on mouse movement
+ float fYawDelta = -m_vRotVelocity.x;
+ float fPitchDelta = m_vRotVelocity.y;
+
+ // Invert pitch if requested
+ if( m_bInvertPitch )
+ fPitchDelta = -fPitchDelta;
+
+ m_fCameraPitchAngle += fPitchDelta;
+ m_fCameraYawAngle += fYawDelta;
+
+ // Limit pitch to straight up or straight down
+ m_fCameraPitchAngle = max(-XM_PI / 2.0f, m_fCameraPitchAngle);
+ m_fCameraPitchAngle = min(+XM_PI / 2.0f, m_fCameraPitchAngle);
+ }
+
+ // Make a rotation matrix based on the camera's yaw & pitch
+ XMMATRIX mCameraRot = XMMatrixRotationRollPitchYaw(m_fCameraPitchAngle, m_fCameraYawAngle, 0.0f);
+
+ // Transform vectors based on camera's rotation matrix
+ XMVECTOR vLocalUp = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
+ XMVECTOR vLocalAhead = XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f);
+ XMVECTOR vWorldUp = XMVector3TransformCoord(vLocalUp, mCameraRot);
+ XMVECTOR vWorldAhead = XMVector3TransformCoord(vLocalAhead, mCameraRot);
+
+ // Transform the position delta by the camera's rotation
+ if (!m_bEnableYAxisMovement)
+ {
+ // If restricting Y movement, do not include pitch
+ // when transforming position delta vector.
+ mCameraRot = XMMatrixRotationRollPitchYaw(0.0f, m_fCameraYawAngle, 0.f);
+ }
+ XMVECTOR vPosDeltaWorld = XMVector3TransformCoord(vPosDelta, mCameraRot);
+
+ // Move the eye position
+ XMVECTOR vEye = XMLoadFloat3(&m_vEye) + vPosDeltaWorld;
+ XMStoreFloat3(&m_vEye, vEye);
+
+ if (m_bClipToBoundary)
+ ConstrainToBoundary(vEye);
+
+ // Update the lookAt position based on the eye position
+ XMVECTOR vLookAt = vEye + vWorldAhead;
+ XMStoreFloat3(&m_vLookAt, vLookAt);
+
+ // Update the view matrix
+ XMMATRIX mView = XMMatrixLookAtRH(vEye, vLookAt, vWorldUp);
+ XMStoreFloat4x4(&m_mView, mView);
+ XMStoreFloat4x4(&m_mCameraWorld, XMMatrixInverse(nullptr, mView));
+}
+
+void CFirstPersonCameraRH::SetProjParams(FLOAT fFOV, FLOAT fAspect, FLOAT fNearPlane, FLOAT fFarPlane)
+{
+ // Set attributes for the projection matrix
+ m_fFOV = fFOV;
+ m_fAspect = fAspect;
+ m_fNearPlane = fNearPlane;
+ m_fFarPlane = fFarPlane;
+
+ XMStoreFloat4x4(&m_mProj, XMMatrixPerspectiveFovRH(fFOV, fAspect, fNearPlane, fFarPlane));
+}
+
+
+
+// CShadowMap implementation
+
+CShadowMap::CShadowMap()
+: m_pDsv(nullptr),
+ m_pSrv(nullptr),
+ m_size(0),
+ m_vecLight(0.0f, 0.0f, 0.0f),
+ m_posMinScene(FLT_MAX, FLT_MAX, FLT_MAX),
+ m_posMaxScene(-FLT_MAX, -FLT_MAX, -FLT_MAX),
+ m_matWorldToClip(),
+ m_matWorldToUvzw(),
+ m_vecDiam()
+{
+}
+
+HRESULT CShadowMap::Init(unsigned int size, ID3D11Device * pDevice)
+{
+ HRESULT hr;
+
+ // Create 2D texture for shadow map
+ D3D11_TEXTURE2D_DESC texDesc =
+ {
+ size, size, // width, height
+ 1, 1, // mip levels, array size
+ DXGI_FORMAT_R32_TYPELESS,
+ { 1, 0 }, // multisample count, quality
+ D3D11_USAGE_DEFAULT,
+ D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_DEPTH_STENCIL,
+ 0, // no cpu access
+ 0, // no misc flags
+ };
+ ID3D11Texture2D * pTex = nullptr;
+ V_RETURN(pDevice->CreateTexture2D(&texDesc, nullptr, &pTex));
+
+ // Create depth-stencil view
+ D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc =
+ {
+ DXGI_FORMAT_D32_FLOAT,
+ D3D11_DSV_DIMENSION_TEXTURE2D,
+ };
+ V_RETURN(pDevice->CreateDepthStencilView(pTex, &dsvDesc, &m_pDsv));
+
+ // Create shader resource view
+ D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc =
+ {
+ DXGI_FORMAT_R32_FLOAT,
+ D3D11_SRV_DIMENSION_TEXTURE2D,
+ };
+ srvDesc.Texture2D.MipLevels = 1;
+ V_RETURN(pDevice->CreateShaderResourceView(pTex, &srvDesc, &m_pSrv));
+
+ // The texture isn't needed any more
+ SAFE_RELEASE(pTex);
+
+ m_size = size;
+
+ SetDebugName(m_pDsv, "Shadow map - DSV");
+ SetDebugName(m_pSrv, "Shadow map - SRV");
+ DebugPrintf(L"Created shadow map, format D32_FLOAT, %d x %d\n", size, size);
+
+ return S_OK;
+}
+
+void CShadowMap::UpdateMatrix()
+{
+ // Calculate view matrix based on light direction
+
+ XMVECTOR posEye = XMVectorZero();
+ XMVECTOR posLookAt = posEye - XMLoadFloat3(&m_vecLight);
+ XMVECTOR vecUp = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
+
+ // Handle light vector being straight up or down
+ if (fabsf(m_vecLight.x) < 1e-4f && fabsf(m_vecLight.z) < 1e-4f) {
+ vecUp = XMVectorSet(1.0f, 0.0f, 0.0f, 0.0f);
+ }
+
+ XMMATRIX matView = XMMatrixLookAtRH(posEye, posLookAt, vecUp);
+
+ // Transform scene AABB into view space and recalculate bounds
+
+ XMVECTOR posMinView = XMVectorReplicate(FLT_MAX);
+ XMVECTOR posMaxView = XMVectorReplicate(-FLT_MAX);
+
+ for (int i = 0; i < 8; ++i)
+ {
+ XMVECTOR posWorld = XMVectorSet(
+ (i & 1) ? m_posMaxScene.x : m_posMinScene.x,
+ (i & 2) ? m_posMaxScene.y : m_posMinScene.y,
+ (i & 4) ? m_posMaxScene.z : m_posMinScene.z,
+ 0.0f);
+
+ XMVECTOR posView = XMVector3TransformCoord(posWorld, matView);
+
+ posMinView = XMVectorMin(posMinView, posView);
+ posMaxView = XMVectorMax(posMaxView, posView);
+ }
+
+ XMStoreFloat3(&m_vecDiam, posMaxView - posMinView);
+
+#if 0
+ DebugPrintf(
+ L"Shadow map world-space diameter (cm): %0.2f %0.2f %0.2f\n",
+ m_vecDiam.x, m_vecDiam.y, m_vecDiam.z);
+#endif
+
+ // Calculate orthogonal projection matrix to fit the scene bounds
+ XMMATRIX matProj = XMMatrixOrthographicOffCenterRH(
+ XMVectorGetX(posMinView), XMVectorGetX(posMaxView),
+ XMVectorGetY(posMinView), XMVectorGetY(posMaxView),
+ -XMVectorGetZ(posMaxView), -XMVectorGetZ(posMinView));
+ XMStoreFloat4x4(&m_matProj, matProj);
+
+ XMMATRIX matWorldToClip = matView * matProj;
+ XMStoreFloat4x4(&m_matWorldToClip, matWorldToClip);
+
+ // Calculate matrix that maps to [0, 1] UV space instead of [-1, 1] clip space
+
+ XMMATRIX matClipToUvzw(
+ 0.5f, 0, 0, 0,
+ 0, -0.5f, 0, 0,
+ 0, 0, 1, 0,
+ 0.5f, 0.5f, 0, 1);
+
+ XMMATRIX matWorldToUvzw = matWorldToClip * matClipToUvzw;
+ XMStoreFloat4x4(&m_matWorldToUvzw, matWorldToUvzw);
+
+ // Calculate inverse transpose matrix for transforming normals
+
+ XMMATRIX matWorldToUvzNormal = XMMatrixTranspose(XMMatrixInverse(nullptr, XMMATRIX(
+ matWorldToUvzw.r[0],
+ matWorldToUvzw.r[1],
+ matWorldToUvzw.r[2],
+ XMVectorSelect(matWorldToUvzw.r[3], g_XMZero, g_XMSelect1110)
+ )));
+ XMStoreFloat4x4(&m_matWorldToUvzNormal, matWorldToUvzNormal);
+}
+
+void CShadowMap::BindRenderTarget(ID3D11DeviceContext * pCtx)
+{
+ D3D11_VIEWPORT viewport =
+ {
+ 0.0f, 0.0f, // left, top
+ float(m_size), float(m_size), // width, height
+ 0.0f, 1.0f, // min/max depth
+ };
+
+ pCtx->RSSetViewports(1, &viewport);
+ pCtx->OMSetRenderTargets(0, nullptr, m_pDsv);
+}
+
+XMFLOAT3 CShadowMap::CalcFilterUVZScale(float filterRadius) const
+{
+ // Expand the filter in the Z direction (this controls how far
+ // the filter can tilt before it starts contracting).
+ // Tuned empirically.
+ float zScale = 4.0f;
+
+ return XMFLOAT3(
+ filterRadius / m_vecDiam.x,
+ filterRadius / m_vecDiam.y,
+ zScale * filterRadius / m_vecDiam.z);
+}
+
+
+
+// CVarShadowMap implementation
+
+extern CMesh g_meshFullscreen;
+
+CVarShadowMap::CVarShadowMap()
+: m_pRtv(nullptr),
+ m_pSrv(nullptr),
+ m_pRtvTemp(nullptr),
+ m_pSrvTemp(nullptr),
+ m_size(0),
+ m_blurRadius(1.0f)
+{
+}
+
+HRESULT CVarShadowMap::Init(unsigned int size, ID3D11Device * pDevice)
+{
+ HRESULT hr;
+
+ // Create 2D textures for VSM and temp VSM for blur
+ D3D11_TEXTURE2D_DESC texDesc =
+ {
+ size, size, // width, height
+ 1, 1, // mip levels, array size
+ DXGI_FORMAT_R32G32_FLOAT,
+ { 1, 0 }, // multisample count, quality
+ D3D11_USAGE_DEFAULT,
+ D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET,
+ 0, // no cpu access
+ 0, // no misc flags
+ };
+ ID3D11Texture2D * pTex = nullptr, * pTexTemp = nullptr;
+ V_RETURN(pDevice->CreateTexture2D(&texDesc, nullptr, &pTex));
+ V_RETURN(pDevice->CreateTexture2D(&texDesc, nullptr, &pTexTemp));
+
+ // Create render target views
+ D3D11_RENDER_TARGET_VIEW_DESC rtvDesc =
+ {
+ DXGI_FORMAT_R32G32_FLOAT,
+ D3D11_RTV_DIMENSION_TEXTURE2D,
+ };
+ V_RETURN(pDevice->CreateRenderTargetView(pTex, &rtvDesc, &m_pRtv));
+ V_RETURN(pDevice->CreateRenderTargetView(pTexTemp, &rtvDesc, &m_pRtvTemp));
+
+ // Create shader resource views
+ D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc =
+ {
+ DXGI_FORMAT_R32G32_FLOAT,
+ D3D11_SRV_DIMENSION_TEXTURE2D,
+ };
+ srvDesc.Texture2D.MipLevels = 1;
+ V_RETURN(pDevice->CreateShaderResourceView(pTex, &srvDesc, &m_pSrv));
+ V_RETURN(pDevice->CreateShaderResourceView(pTexTemp, &srvDesc, &m_pSrvTemp));
+
+ // The textures aren't needed any more
+ SAFE_RELEASE(pTex);
+ SAFE_RELEASE(pTexTemp);
+
+ m_size = size;
+
+ SetDebugName(m_pRtv, "VSM - RTV");
+ SetDebugName(m_pSrv, "VSM - SRV");
+ SetDebugName(m_pRtvTemp, "VSM - temp RTV");
+ SetDebugName(m_pSrvTemp, "VSM - temp SRV");
+ DebugPrintf(L"Created VSM, format R32G32_FLOAT, %d x %d\n", size, size);
+
+ return S_OK;
+}
+
+void CVarShadowMap::UpdateFromShadowMap(const CShadowMap & shadow, ID3D11DeviceContext * pCtx)
+{
+ D3D11_VIEWPORT viewport =
+ {
+ 0.0f, 0.0f, // left, top
+ float(m_size), float(m_size), // width, height
+ 0.0f, 1.0f, // min/max depth
+ };
+
+ pCtx->RSSetViewports(1, &viewport);
+ pCtx->OMSetRenderTargets(1, &m_pRtv, nullptr);
+
+ g_shdmgr.BindCreateVSM(pCtx, shadow.m_pSrv);
+ g_meshFullscreen.Draw(pCtx);
+}
+
+void CVarShadowMap::GaussianBlur(ID3D11DeviceContext * pCtx)
+{
+ D3D11_VIEWPORT viewport =
+ {
+ 0.0f, 0.0f, // left, top
+ float(m_size), float(m_size), // width, height
+ 0.0f, 1.0f, // min/max depth
+ };
+
+ pCtx->RSSetViewports(1, &viewport);
+ pCtx->OMSetRenderTargets(1, &m_pRtvTemp, nullptr);
+
+ g_shdmgr.BindGaussian(pCtx, m_pSrv, m_blurRadius, 0.0f);
+ g_meshFullscreen.Draw(pCtx);
+
+ pCtx->OMSetRenderTargets(0, nullptr, nullptr);
+ g_shdmgr.BindGaussian(pCtx, m_pSrvTemp, 0.0f, m_blurRadius);
+ pCtx->OMSetRenderTargets(1, &m_pRtv, nullptr);
+ g_meshFullscreen.Draw(pCtx);
+}
+
+
+
+// CGpuProfiler implementation
+
+CGpuProfiler g_gpuProfiler;
+
+CGpuProfiler::CGpuProfiler()
+: m_iFrameQuery(0),
+ m_iFrameCollect(-1),
+ m_apQueryTsDisjoint(),
+ m_apQueryTs(),
+ m_fTsUsed(),
+ m_adT(),
+ m_gpuFrameTime(0.0f),
+ m_adTAvg(),
+ m_gpuFrameTimeAvg(0.0f),
+ m_adTTotal(),
+ m_gpuFrameTimeTotal(0.0f),
+ m_frameCount(0),
+ m_tBeginAvg(0)
+{
+}
+
+HRESULT CGpuProfiler::Init(ID3D11Device * pDevice)
+{
+ HRESULT hr;
+
+ // Create all the queries we'll need
+
+ D3D11_QUERY_DESC queryDesc = { D3D11_QUERY_TIMESTAMP_DISJOINT, 0 };
+ V_RETURN(pDevice->CreateQuery(&queryDesc, &m_apQueryTsDisjoint[0]));
+ V_RETURN(pDevice->CreateQuery(&queryDesc, &m_apQueryTsDisjoint[1]));
+
+ queryDesc.Query = D3D11_QUERY_TIMESTAMP;
+ for (GTS gts = GTS_BeginFrame; gts < GTS_Max; gts = GTS(gts + 1))
+ {
+ V_RETURN(pDevice->CreateQuery(&queryDesc, &m_apQueryTs[gts][0]));
+ V_RETURN(pDevice->CreateQuery(&queryDesc, &m_apQueryTs[gts][1]));
+ }
+
+ timeBeginPeriod(1);
+
+ return S_OK;
+}
+
+void CGpuProfiler::Release()
+{
+ SAFE_RELEASE(m_apQueryTsDisjoint[0]);
+ SAFE_RELEASE(m_apQueryTsDisjoint[1]);
+
+ for (GTS gts = GTS_BeginFrame; gts < GTS_Max; gts = GTS(gts + 1))
+ {
+ SAFE_RELEASE(m_apQueryTs[gts][0]);
+ SAFE_RELEASE(m_apQueryTs[gts][1]);
+ }
+
+ timeEndPeriod(1);
+}
+
+void CGpuProfiler::BeginFrame(ID3D11DeviceContext * pCtx)
+{
+ pCtx->Begin(m_apQueryTsDisjoint[m_iFrameQuery]);
+ Timestamp(pCtx, GTS_BeginFrame);
+}
+
+void CGpuProfiler::Timestamp(ID3D11DeviceContext * pCtx, GTS gts)
+{
+ pCtx->End(m_apQueryTs[gts][m_iFrameQuery]);
+ m_fTsUsed[gts][m_iFrameQuery] = true;
+}
+
+void CGpuProfiler::EndFrame(ID3D11DeviceContext * pCtx)
+{
+ Timestamp(pCtx, GTS_EndFrame);
+ pCtx->End(m_apQueryTsDisjoint[m_iFrameQuery]);
+
+ ++m_iFrameQuery &= 1;
+}
+
+void CGpuProfiler::WaitForDataAndUpdate(ID3D11DeviceContext * pCtx)
+{
+ if (m_iFrameCollect < 0)
+ {
+ // Haven't run enough frames yet to have data
+ m_iFrameCollect = 0;
+ return;
+ }
+
+ int iFrame = m_iFrameCollect;
+ ++m_iFrameCollect &= 1;
+
+ if (!m_fTsUsed[GTS_BeginFrame][iFrame] ||
+ !m_fTsUsed[GTS_EndFrame][iFrame])
+ {
+ DebugPrintf(L"Couldn't analyze timestamp data because begin and end frame timestamps weren't recorded\n");
+ return;
+ }
+
+ // Wait for data
+ while (pCtx->GetData(m_apQueryTsDisjoint[iFrame], nullptr, 0, 0) == S_FALSE)
+ {
+ Sleep(1);
+ }
+
+ D3D11_QUERY_DATA_TIMESTAMP_DISJOINT timestampDisjoint;
+ if (pCtx->GetData(m_apQueryTsDisjoint[iFrame], &timestampDisjoint, sizeof(timestampDisjoint), 0) != S_OK)
+ {
+ DebugPrintf(L"Couldn't retrieve timestamp disjoint query data\n");
+ return;
+ }
+
+ if (timestampDisjoint.Disjoint)
+ {
+ // Throw out this frame's data
+ DebugPrintf(L"Timestamps disjoint\n");
+ return;
+ }
+
+ // Wait for data
+ while (pCtx->GetData(m_apQueryTs[GTS_BeginFrame][iFrame], nullptr, 0, 0) == S_FALSE)
+ {
+ Sleep(1);
+ }
+
+ UINT64 timestampBeginFrame;
+ if (pCtx->GetData(m_apQueryTs[GTS_BeginFrame][iFrame], &timestampBeginFrame, sizeof(UINT64), 0) != S_OK)
+ {
+ DebugPrintf(L"Couldn't retrieve timestamp query data for GTS %d\n", GTS_BeginFrame);
+ return;
+ }
+
+ UINT64 timestampPrev = timestampBeginFrame;
+ UINT64 timestampEndFrame = 0;
+ for (GTS gts = GTS(GTS_BeginFrame + 1); gts < GTS_Max; gts = GTS(gts + 1))
+ {
+ UINT64 timestamp;
+ if (m_fTsUsed[gts][iFrame])
+ {
+ // Wait for data
+ while (pCtx->GetData(m_apQueryTs[gts][iFrame], nullptr, 0, 0) == S_FALSE)
+ {
+ Sleep(1);
+ }
+
+ if (pCtx->GetData(m_apQueryTs[gts][iFrame], &timestamp, sizeof(UINT64), 0) != S_OK)
+ {
+ DebugPrintf(L"Couldn't retrieve timestamp query data for GTS %d\n", gts);
+ return;
+ }
+ }
+ else
+ {
+ // Timestamp wasn't used in the frame we're collecting;
+ // just pretend it took zero time
+ timestamp = timestampPrev;
+ }
+
+ if (gts == GTS_EndFrame)
+ timestampEndFrame = timestamp;
+
+ m_adT[gts] = float(timestamp - timestampPrev) / float(timestampDisjoint.Frequency);
+ timestampPrev = timestamp;
+
+ m_adTTotal[gts] += m_adT[gts];
+
+ // Reset timestamp-used flags for new frame
+ m_fTsUsed[gts][iFrame] = false;
+ }
+
+ m_gpuFrameTime = float(timestampEndFrame - timestampBeginFrame) / float(timestampDisjoint.Frequency);
+ m_gpuFrameTimeTotal += m_gpuFrameTime;
+
+ ++m_frameCount;
+ DWORD curTime = timeGetTime();
+ if (curTime > m_tBeginAvg + 500)
+ {
+ for (GTS gts = GTS_BeginFrame; gts < GTS_Max; gts = GTS(gts + 1))
+ {
+ m_adTAvg[gts] = m_adTTotal[gts] / m_frameCount;
+ m_adTTotal[gts] = 0.0f;
+ }
+
+ m_gpuFrameTimeAvg = m_gpuFrameTimeTotal / m_frameCount;
+ m_gpuFrameTimeTotal = 0.0f;
+
+ m_frameCount = 0;
+ m_tBeginAvg = curTime;
+ }
+}
diff --git a/samples/d3d11/util.h b/samples/d3d11/util.h
new file mode 100644
index 0000000..ad091bc
--- /dev/null
+++ b/samples/d3d11/util.h
@@ -0,0 +1,262 @@
+//----------------------------------------------------------------------------------
+// File: FaceWorks/samples/sample_d3d11/util.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.
+//
+//----------------------------------------------------------------------------------
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include <DXUT/Core/DXUT.h>
+#include <DXUT/Optional/DXUTcamera.h>
+
+// Get the dimension of a static array
+template <typename T, int N> char (&dim_helper(T (&)[N]))[N];
+#define dim(x) (sizeof(dim_helper(x)))
+#define dim_field(S, m) (dim(((S*)0)->m))
+#define sizeof_field(S, m) (sizeof(((S*)0)->m))
+
+
+
+// General utilities
+std::wstring StrPrintf(const wchar_t * fmt, ...);
+void DebugPrintf(const wchar_t * fmt, ...);
+HRESULT LoadFile(const wchar_t * strFilename, std::vector<char> * pData, bool bText = false);
+const wchar_t * BaseFilename(const wchar_t * strFilename);
+void SetDebugName(ID3D11DeviceChild * pD3DObject, const char * strName);
+void SetDebugName(ID3D11DeviceChild * pD3DObject, const wchar_t * strName);
+
+
+
+// Mesh data & loading
+
+struct Vertex
+{
+ DirectX::XMFLOAT3 m_pos;
+ DirectX::XMFLOAT3 m_normal;
+ DirectX::XMFLOAT2 m_uv;
+ DirectX::XMFLOAT3 m_tangent;
+ float m_curvature;
+};
+
+class CMesh
+{
+public:
+ std::vector<Vertex> m_verts;
+ std::vector<int> m_indices;
+
+ ID3D11Buffer * m_pVtxBuffer;
+ ID3D11Buffer * m_pIdxBuffer;
+ UINT m_vtxStride; // Vertex stride for IASetVertexBuffers
+ UINT m_cIdx; // Index count for DrawIndexed
+ D3D11_PRIMITIVE_TOPOLOGY m_primtopo;
+ DirectX::XMFLOAT3 m_posMin, m_posMax; // Bounding box in local space
+ DirectX::XMFLOAT3 m_posCenter; // Center of bounding box
+ float m_diameter; // Diameter of bounding box
+ float m_uvScale; // Average world-space size of 1 UV unit
+
+ CMesh();
+ void Draw(ID3D11DeviceContext * pCtx);
+ void Release();
+};
+
+HRESULT CreateFullscreenMesh(ID3D11Device * pDevice, CMesh * pMesh);
+HRESULT LoadObjMesh(
+ const wchar_t * strFilename,
+ ID3D11Device * pDevice,
+ CMesh * pMesh);
+
+
+
+// Texture loading
+
+enum LTFLAGS
+{
+ LT_None = 0,
+ LT_Mipmap = 1,
+ LT_HDR = 2,
+ LT_Cubemap = 4,
+ LT_Linear = 8,
+};
+
+HRESULT LoadTexture(
+ const wchar_t * strFilename,
+ ID3D11Device * pDevice,
+ ID3D11DeviceContext * pDeviceContext,
+ ID3D11ShaderResourceView ** ppSrv,
+ int flags = LT_Mipmap);
+
+HRESULT LoadTexture(
+ const wchar_t * strFilename,
+ ID3D11Device * pDevice,
+ ID3D11ShaderResourceView ** ppSrv,
+ int flags = 0);
+
+
+
+// Camera class, based on DXUT camera but with Maya-style navigation
+class CMayaStyleCamera : public CBaseCamera
+{
+public:
+ CMayaStyleCamera();
+
+ virtual void FrameMove(FLOAT fElapsedTime) override;
+ virtual void SetProjParams(FLOAT fFOV, FLOAT fAspect, FLOAT fNearPlane, FLOAT fFarPlane) override;
+ virtual void SetViewParams(DirectX::FXMVECTOR pvEyePt, DirectX::FXMVECTOR pvLookatPt) override;
+
+protected:
+ float m_fRadius; // Distance of orbit
+};
+
+// First-person camera class with right-handed matrices
+class CFirstPersonCameraRH : public CFirstPersonCamera
+{
+public:
+ virtual void FrameMove(FLOAT fElapsedTime) override;
+ virtual void SetProjParams(FLOAT fFOV, FLOAT fAspect, FLOAT fNearPlane, FLOAT fFarPlane) override;
+};
+
+
+
+// Very simple shadow map class, fits an orthogonal shadow map around a scene bounding box
+class CShadowMap
+{
+public:
+ ID3D11DepthStencilView * m_pDsv;
+ ID3D11ShaderResourceView * m_pSrv;
+ int m_size; // Shadow map resolution
+ DirectX::XMFLOAT3 m_vecLight; // Unit vector toward directional light
+ DirectX::XMFLOAT3 m_posMinScene, m_posMaxScene; // AABB of scene in world space
+ DirectX::XMFLOAT4X4 m_matProj; // Projection matrix
+ DirectX::XMFLOAT4X4 m_matWorldToClip; // Matrix for rendering shadow map
+ DirectX::XMFLOAT4X4 m_matWorldToUvzw; // Matrix for sampling shadow map
+ DirectX::XMFLOAT4X4 m_matWorldToUvzNormal; // Matrix for transforming normals to shadow map space
+ DirectX::XMFLOAT3 m_vecDiam; // Diameter in world units along shadow XYZ axes
+
+ CShadowMap();
+
+ HRESULT Init(unsigned int size, ID3D11Device * pDevice);
+ void UpdateMatrix();
+ void BindRenderTarget(ID3D11DeviceContext * pCtx);
+
+ DirectX::XMFLOAT3 CalcFilterUVZScale(float filterRadius) const;
+
+ void Release()
+ {
+ SAFE_RELEASE(m_pDsv);
+ SAFE_RELEASE(m_pSrv);
+ }
+};
+
+
+
+// Variance shadow map
+class CVarShadowMap
+{
+public:
+ ID3D11RenderTargetView * m_pRtv; // Main RT, stores (z, z^2)
+ ID3D11ShaderResourceView * m_pSrv;
+ ID3D11RenderTargetView * m_pRtvTemp; // Temp RT for Gaussian blur
+ ID3D11ShaderResourceView * m_pSrvTemp;
+ int m_size; // Shadow map resolution
+ float m_blurRadius; // Radius of Gaussian in UV space
+
+ CVarShadowMap();
+
+ HRESULT Init(unsigned int size, ID3D11Device * pDevice);
+ void UpdateFromShadowMap(const CShadowMap & shadow, ID3D11DeviceContext * pCtx);
+ void GaussianBlur(ID3D11DeviceContext * pCtx);
+
+ void Release()
+ {
+ SAFE_RELEASE(m_pRtv);
+ SAFE_RELEASE(m_pSrv);
+ SAFE_RELEASE(m_pRtvTemp);
+ SAFE_RELEASE(m_pSrvTemp);
+ }
+};
+
+
+
+// Perf measurement
+
+// Enum of GPU timestamps to record
+enum GTS
+{
+ GTS_BeginFrame,
+ GTS_ShadowMap,
+ GTS_Skin,
+ GTS_Eyes,
+ GTS_EndFrame,
+ GTS_Max
+};
+
+class CGpuProfiler
+{
+public:
+ CGpuProfiler();
+
+ HRESULT Init(ID3D11Device * pDevice);
+ void Release();
+
+ void BeginFrame(ID3D11DeviceContext * pCtx);
+ void Timestamp(ID3D11DeviceContext * pCtx, GTS gts);
+ void EndFrame(ID3D11DeviceContext * pCtx);
+
+ // Wait on GPU for last frame's data (not the current frame's) to be available
+ void WaitForDataAndUpdate(ID3D11DeviceContext * pCtx);
+
+ float Dt(GTS gts) const { return m_adT[gts]; }
+ float GPUFrameTime() const { return m_gpuFrameTime; }
+ float DtAvg(GTS gts) const { return m_adTAvg[gts]; }
+ float GPUFrameTimeAvg() const { return m_gpuFrameTimeAvg; }
+
+protected:
+ int m_iFrameQuery; // Which of the two sets of queries are we currently issuing?
+ int m_iFrameCollect; // Which of the two did we last collect?
+ ID3D11Query * m_apQueryTsDisjoint[2]; // "Timestamp disjoint" query; records whether timestamps are valid
+ ID3D11Query * m_apQueryTs[GTS_Max][2]; // Individual timestamp queries for each relevant point in the frame
+ bool m_fTsUsed[GTS_Max][2]; // Flags recording which timestamps were actually used in a frame
+
+ float m_adT[GTS_Max]; // Last frame's timings (each relative to previous GTS)
+ float m_gpuFrameTime;
+ float m_adTAvg[GTS_Max]; // Timings averaged over 0.5 second
+ float m_gpuFrameTimeAvg;
+
+ float m_adTTotal[GTS_Max]; // Total timings thus far within this averaging period
+ float m_gpuFrameTimeTotal;
+ int m_frameCount; // Frames rendered in current averaging period
+ DWORD m_tBeginAvg; // Time (in ms) at which current averaging period started
+};
+
+extern CGpuProfiler g_gpuProfiler;