diff options
| author | Marco Foco <[email protected]> | 2016-03-07 15:47:07 +0100 |
|---|---|---|
| committer | Marco Foco <[email protected]> | 2016-03-08 16:04:19 +0100 |
| commit | cd6e0492903f8a9eb5efa14263d7d9ab092517de (patch) | |
| tree | 05c010b75bf777335565819dcceb140886c5a7e9 /samples/d3d11 | |
| download | faceworks-cd6e0492903f8a9eb5efa14263d7d9ab092517de.tar.xz faceworks-cd6e0492903f8a9eb5efa14263d7d9ab092517de.zip | |
FaceWorks 1.0
Diffstat (limited to 'samples/d3d11')
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 +// Email: [email protected] +// 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 +// Email: [email protected] +// 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 +// Email: [email protected] +// 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 +// Email: [email protected] +// 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 +// Email: [email protected] +// 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 +// Email: [email protected] +// 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 +// Email: [email protected] +// 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 +// Email: [email protected] +// 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 +// Email: [email protected] +// 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 +// Email: [email protected] +// 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 +// Email: [email protected] +// 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 +// Email: [email protected] +// 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 +// Email: [email protected] +// 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 +// Email: [email protected] +// 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 +// Email: [email protected] +// 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 +// Email: [email protected] +// 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 +// Email: [email protected] +// 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 +// Email: [email protected] +// 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 +// Email: [email protected] +// 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 +// Email: [email protected] +// 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 +// Email: [email protected] +// 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 +// Email: [email protected] +// 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 +// Email: [email protected] +// 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 +// Email: [email protected] +// 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 +// Email: [email protected] +// 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 +// Email: [email protected] +// 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 +// Email: [email protected] +// 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], ×tampDisjoint, 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], ×tampBeginFrame, 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], ×tamp, 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 +// Email: [email protected] +// 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; |