1
0
mirror of https://github.com/ncblakely/GiantsTools synced 2024-11-05 14:55:38 +01:00
GiantsTools/Sdk/External/DirectXTK/Src/PBREffect.cpp
2021-01-23 15:40:09 -08:00

533 lines
15 KiB
C++

//--------------------------------------------------------------------------------------
// File: PBREffect.cpp
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// http://go.microsoft.com/fwlink/?LinkID=615561
//--------------------------------------------------------------------------------------
#include "pch.h"
#include "EffectCommon.h"
using namespace DirectX;
// Constant buffer layout. Must match the shader!
struct PBREffectConstants
{
XMVECTOR eyePosition;
XMMATRIX world;
XMVECTOR worldInverseTranspose[3];
XMMATRIX worldViewProj;
XMMATRIX prevWorldViewProj; // for velocity generation
XMVECTOR lightDirection[IEffectLights::MaxDirectionalLights];
XMVECTOR lightDiffuseColor[IEffectLights::MaxDirectionalLights];
// PBR Parameters
XMVECTOR Albedo;
float Metallic;
float Roughness;
int numRadianceMipLevels;
// Size of render target
float targetWidth;
float targetHeight;
};
static_assert((sizeof(PBREffectConstants) % 16) == 0, "CB size not padded correctly");
// Traits type describes our characteristics to the EffectBase template.
struct PBREffectTraits
{
using ConstantBufferType = PBREffectConstants;
static constexpr int VertexShaderCount = 4;
static constexpr int PixelShaderCount = 5;
static constexpr int ShaderPermutationCount = 10;
static constexpr int RootSignatureCount = 1;
};
// Internal PBREffect implementation class.
class PBREffect::Impl : public EffectBase<PBREffectTraits>
{
public:
Impl(_In_ ID3D11Device* device);
Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> albedoTexture;
Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> normalTexture;
Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> rmaTexture;
Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> emissiveTexture;
Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> radianceTexture;
Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> irradianceTexture;
bool biasedVertexNormals;
bool velocityEnabled;
XMVECTOR lightColor[MaxDirectionalLights];
int GetCurrentShaderPermutation() const noexcept;
void Apply(_In_ ID3D11DeviceContext* deviceContext);
};
// Include the precompiled shader code.
namespace
{
#if defined(_XBOX_ONE) && defined(_TITLE)
#include "Shaders/Compiled/XboxOnePBREffect_VSConstant.inc"
#include "Shaders/Compiled/XboxOnePBREffect_VSConstantVelocity.inc"
#include "Shaders/Compiled/XboxOnePBREffect_VSConstantBn.inc"
#include "Shaders/Compiled/XboxOnePBREffect_VSConstantVelocityBn.inc"
#include "Shaders/Compiled/XboxOnePBREffect_PSConstant.inc"
#include "Shaders/Compiled/XboxOnePBREffect_PSTextured.inc"
#include "Shaders/Compiled/XboxOnePBREffect_PSTexturedEmissive.inc"
#include "Shaders/Compiled/XboxOnePBREffect_PSTexturedVelocity.inc"
#include "Shaders/Compiled/XboxOnePBREffect_PSTexturedEmissiveVelocity.inc"
#else
#include "Shaders/Compiled/PBREffect_VSConstant.inc"
#include "Shaders/Compiled/PBREffect_VSConstantVelocity.inc"
#include "Shaders/Compiled/PBREffect_VSConstantBn.inc"
#include "Shaders/Compiled/PBREffect_VSConstantVelocityBn.inc"
#include "Shaders/Compiled/PBREffect_PSConstant.inc"
#include "Shaders/Compiled/PBREffect_PSTextured.inc"
#include "Shaders/Compiled/PBREffect_PSTexturedEmissive.inc"
#include "Shaders/Compiled/PBREffect_PSTexturedVelocity.inc"
#include "Shaders/Compiled/PBREffect_PSTexturedEmissiveVelocity.inc"
#endif
}
template<>
const ShaderBytecode EffectBase<PBREffectTraits>::VertexShaderBytecode[] =
{
{ PBREffect_VSConstant, sizeof(PBREffect_VSConstant) },
{ PBREffect_VSConstantVelocity, sizeof(PBREffect_VSConstantVelocity) },
{ PBREffect_VSConstantBn, sizeof(PBREffect_VSConstantBn) },
{ PBREffect_VSConstantVelocityBn, sizeof(PBREffect_VSConstantVelocityBn) },
};
template<>
const int EffectBase<PBREffectTraits>::VertexShaderIndices[] =
{
0, // constant
0, // textured
0, // textured + emissive
1, // textured + velocity
1, // textured + emissive + velocity
2, // constant (biased vertex normals)
2, // textured (biased vertex normals)
2, // textured + emissive (biased vertex normals)
3, // textured + velocity (biased vertex normals)
3, // textured + emissive + velocity (biasoed vertex normals)
};
template<>
const ShaderBytecode EffectBase<PBREffectTraits>::PixelShaderBytecode[] =
{
{ PBREffect_PSConstant, sizeof(PBREffect_PSConstant) },
{ PBREffect_PSTextured, sizeof(PBREffect_PSTextured) },
{ PBREffect_PSTexturedEmissive, sizeof(PBREffect_PSTexturedEmissive) },
{ PBREffect_PSTexturedVelocity, sizeof(PBREffect_PSTexturedVelocity) },
{ PBREffect_PSTexturedEmissiveVelocity, sizeof(PBREffect_PSTexturedEmissiveVelocity) }
};
template<>
const int EffectBase<PBREffectTraits>::PixelShaderIndices[] =
{
0, // constant
1, // textured
2, // textured + emissive
3, // textured + velocity
4, // textured + emissive + velocity
0, // constant (biased vertex normals)
1, // textured (biased vertex normals)
2, // textured + emissive (biased vertex normals)
3, // textured + velocity (biased vertex normals)
4, // textured + emissive + velocity (biased vertex normals)
};
// Global pool of per-device PBREffect resources. Required by EffectBase<>, but not used.
template<>
SharedResourcePool<ID3D11Device*, EffectBase<PBREffectTraits>::DeviceResources> EffectBase<PBREffectTraits>::deviceResourcesPool = {};
// Constructor.
PBREffect::Impl::Impl(_In_ ID3D11Device* device)
: EffectBase(device),
biasedVertexNormals(false),
velocityEnabled(false),
lightColor{}
{
if (device->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0)
{
throw std::exception("PBREffect requires Feature Level 10.0 or later");
}
static_assert(_countof(EffectBase<PBREffectTraits>::VertexShaderIndices) == PBREffectTraits::ShaderPermutationCount, "array/max mismatch");
static_assert(_countof(EffectBase<PBREffectTraits>::VertexShaderBytecode) == PBREffectTraits::VertexShaderCount, "array/max mismatch");
static_assert(_countof(EffectBase<PBREffectTraits>::PixelShaderBytecode) == PBREffectTraits::PixelShaderCount, "array/max mismatch");
static_assert(_countof(EffectBase<PBREffectTraits>::PixelShaderIndices) == PBREffectTraits::ShaderPermutationCount, "array/max mismatch");
// Lighting
static const XMVECTORF32 defaultLightDirection = { { { 0, -1, 0, 0 } } };
for (int i = 0; i < MaxDirectionalLights; i++)
{
lightColor[i] = g_XMOne;
constants.lightDirection[i] = defaultLightDirection;
constants.lightDiffuseColor[i] = g_XMZero;
}
// Default PBR values
constants.Albedo = g_XMOne;
constants.Metallic = 0.5f;
constants.Roughness = 0.2f;
constants.numRadianceMipLevels = 1;
}
int PBREffect::Impl::GetCurrentShaderPermutation() const noexcept
{
int permutation = 0;
// Textured RMA vs. constant albedo/roughness/metalness?
if (velocityEnabled)
{
// Optional velocity buffer (implies textured RMA)?
permutation = 3;
}
else if (albedoTexture)
{
permutation = 1;
}
// Using an emissive texture?
if (emissiveTexture)
{
permutation += 1;
}
if (biasedVertexNormals)
{
// Compressed normals need to be scaled and biased in the vertex shader.
permutation += 5;
}
return permutation;
}
// Sets our state onto the D3D device.
void PBREffect::Impl::Apply(_In_ ID3D11DeviceContext* deviceContext)
{
// Store old wvp for velocity calculation in shader
constants.prevWorldViewProj = constants.worldViewProj;
// Compute derived parameter values.
matrices.SetConstants(dirtyFlags, constants.worldViewProj);
// World inverse transpose matrix.
if (dirtyFlags & EffectDirtyFlags::WorldInverseTranspose)
{
constants.world = XMMatrixTranspose(matrices.world);
XMMATRIX worldInverse = XMMatrixInverse(nullptr, matrices.world);
constants.worldInverseTranspose[0] = worldInverse.r[0];
constants.worldInverseTranspose[1] = worldInverse.r[1];
constants.worldInverseTranspose[2] = worldInverse.r[2];
dirtyFlags &= ~EffectDirtyFlags::WorldInverseTranspose;
dirtyFlags |= EffectDirtyFlags::ConstantBuffer;
}
// Eye position vector.
if (dirtyFlags & EffectDirtyFlags::EyePosition)
{
XMMATRIX viewInverse = XMMatrixInverse(nullptr, matrices.view);
constants.eyePosition = viewInverse.r[3];
dirtyFlags &= ~EffectDirtyFlags::EyePosition;
dirtyFlags |= EffectDirtyFlags::ConstantBuffer;
}
// Set the textures
if (albedoTexture)
{
ID3D11ShaderResourceView* textures[] = {
albedoTexture.Get(), normalTexture.Get(), rmaTexture.Get(),
emissiveTexture.Get(),
radianceTexture.Get(), irradianceTexture.Get() };
deviceContext->PSSetShaderResources(0, _countof(textures), textures);
}
else
{
ID3D11ShaderResourceView* textures[] = {
nullptr, nullptr, nullptr,
nullptr,
radianceTexture.Get(), irradianceTexture.Get() };
deviceContext->PSSetShaderResources(0, _countof(textures), textures);
}
// Set shaders and constant buffers.
ApplyShaders(deviceContext, GetCurrentShaderPermutation());
}
// Public constructor.
PBREffect::PBREffect(_In_ ID3D11Device* device)
: pImpl(std::make_unique<Impl>(device))
{
}
// Move constructor.
PBREffect::PBREffect(PBREffect&& moveFrom) noexcept
: pImpl(std::move(moveFrom.pImpl))
{
}
// Move assignment.
PBREffect& PBREffect::operator= (PBREffect&& moveFrom) noexcept
{
pImpl = std::move(moveFrom.pImpl);
return *this;
}
// Public destructor.
PBREffect::~PBREffect()
{
}
// IEffect methods.
void PBREffect::Apply(_In_ ID3D11DeviceContext* deviceContext)
{
pImpl->Apply(deviceContext);
}
void PBREffect::GetVertexShaderBytecode(_Out_ void const** pShaderByteCode, _Out_ size_t* pByteCodeLength)
{
pImpl->GetVertexShaderBytecode(pImpl->GetCurrentShaderPermutation(), pShaderByteCode, pByteCodeLength);
}
// Camera settings.
void XM_CALLCONV PBREffect::SetWorld(FXMMATRIX value)
{
pImpl->matrices.world = value;
pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::WorldInverseTranspose;
}
void XM_CALLCONV PBREffect::SetView(FXMMATRIX value)
{
pImpl->matrices.view = value;
pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::EyePosition;
}
void XM_CALLCONV PBREffect::SetProjection(FXMMATRIX value)
{
pImpl->matrices.projection = value;
pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj;
}
void XM_CALLCONV PBREffect::SetMatrices(FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection)
{
pImpl->matrices.world = world;
pImpl->matrices.view = view;
pImpl->matrices.projection = projection;
pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::WorldInverseTranspose | EffectDirtyFlags::EyePosition;
}
// Light settings
void PBREffect::SetLightingEnabled(bool value)
{
if (!value)
{
throw std::exception("PBREffect does not support turning off lighting");
}
}
void PBREffect::SetPerPixelLighting(bool)
{
// Unsupported interface method.
}
void XM_CALLCONV PBREffect::SetAmbientLightColor(FXMVECTOR)
{
// Unsupported interface.
}
void PBREffect::SetLightEnabled(int whichLight, bool value)
{
EffectLights::ValidateLightIndex(whichLight);
pImpl->constants.lightDiffuseColor[whichLight] = (value) ? pImpl->lightColor[whichLight] : g_XMZero;
pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;
}
void XM_CALLCONV PBREffect::SetLightDirection(int whichLight, FXMVECTOR value)
{
EffectLights::ValidateLightIndex(whichLight);
pImpl->constants.lightDirection[whichLight] = value;
pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;
}
void XM_CALLCONV PBREffect::SetLightDiffuseColor(int whichLight, FXMVECTOR value)
{
EffectLights::ValidateLightIndex(whichLight);
pImpl->lightColor[whichLight] = value;
pImpl->constants.lightDiffuseColor[whichLight] = value;
pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;
}
void XM_CALLCONV PBREffect::SetLightSpecularColor(int, FXMVECTOR)
{
// Unsupported interface.
}
void PBREffect::EnableDefaultLighting()
{
EffectLights::EnableDefaultLighting(this);
}
// PBR Settings
void PBREffect::SetAlpha(float value)
{
// Set w to new value, but preserve existing xyz (constant albedo).
pImpl->constants.Albedo = XMVectorSetW(pImpl->constants.Albedo, value);
pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;
}
void PBREffect::SetConstantAlbedo(FXMVECTOR value)
{
// Set xyz to new value, but preserve existing w (alpha).
pImpl->constants.Albedo = XMVectorSelect(pImpl->constants.Albedo, value, g_XMSelect1110);
pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;
}
void PBREffect::SetConstantMetallic(float value)
{
pImpl->constants.Metallic = value;
pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;
}
void PBREffect::SetConstantRoughness(float value)
{
pImpl->constants.Roughness = value;
pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;
}
// Texture settings.
void PBREffect::SetAlbedoTexture(_In_opt_ ID3D11ShaderResourceView* value)
{
pImpl->albedoTexture = value;
}
void PBREffect::SetNormalTexture(_In_opt_ ID3D11ShaderResourceView* value)
{
pImpl->normalTexture = value;
}
void PBREffect::SetRMATexture(_In_opt_ ID3D11ShaderResourceView* value)
{
pImpl->rmaTexture = value;
}
void PBREffect::SetEmissiveTexture(_In_opt_ ID3D11ShaderResourceView* value)
{
pImpl->emissiveTexture = value;
}
void PBREffect::SetSurfaceTextures(
_In_opt_ ID3D11ShaderResourceView* albedo,
_In_opt_ ID3D11ShaderResourceView* normal,
_In_opt_ ID3D11ShaderResourceView* roughnessMetallicAmbientOcclusion)
{
pImpl->albedoTexture = albedo;
pImpl->normalTexture = normal;
pImpl->rmaTexture = roughnessMetallicAmbientOcclusion;
}
void PBREffect::SetIBLTextures(
_In_opt_ ID3D11ShaderResourceView* radiance,
int numRadianceMips,
_In_opt_ ID3D11ShaderResourceView* irradiance)
{
pImpl->radianceTexture = radiance;
pImpl->irradianceTexture = irradiance;
pImpl->constants.numRadianceMipLevels = numRadianceMips;
pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;
}
// Normal compression settings.
void PBREffect::SetBiasedVertexNormals(bool value)
{
pImpl->biasedVertexNormals = value;
}
// Additional settings.
void PBREffect::SetVelocityGeneration(bool value)
{
pImpl->velocityEnabled = value;
}
void PBREffect::SetRenderTargetSizeInPixels(int width, int height)
{
pImpl->constants.targetWidth = static_cast<float>(width);
pImpl->constants.targetHeight = static_cast<float>(height);
pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer;
}