Refactor specular lighting to properly map specular as reflectance in BRDF
Reference: https://google.github.io/filament/Filament.md.html #1492
This commit is contained in:
@@ -190,16 +190,55 @@ Asset::LoadResult Material::load()
|
||||
|
||||
// Load layer
|
||||
layer = MaterialLayer::Load(GetID(), &stream, _shaderHeader.Material.Info, name);
|
||||
if (ContentDeprecated::Clear())
|
||||
const bool upgradeOldSpecular = _shaderHeader.Material.GraphVersion < 177;
|
||||
if (ContentDeprecated::Clear() || upgradeOldSpecular)
|
||||
{
|
||||
// If encountered any deprecated data when loading graph then serialize it
|
||||
MaterialGraph graph;
|
||||
MemoryWriteStream writeStream(1024);
|
||||
stream.SetPosition(0);
|
||||
if (!graph.Load(&stream, true) && !graph.Save(&writeStream, true))
|
||||
if (!graph.Load(&stream, true))
|
||||
{
|
||||
surfaceChunk->Data.Copy(ToSpan(writeStream));
|
||||
ContentDeprecated::Clear();
|
||||
if (upgradeOldSpecular)
|
||||
{
|
||||
// [Deprecated in 1.11]
|
||||
// Specular calculations were changed to support up to 16% of reflectance via ^2 curve instead of linear up to 8%
|
||||
// Insert Custom Code node that converts old materials into a new system to ensure they look the same
|
||||
MaterialGraph::Node* rootNode = nullptr;
|
||||
for (auto& e : graph.Nodes)
|
||||
{
|
||||
if (e.Type == ROOT_NODE_TYPE)
|
||||
{
|
||||
rootNode = &e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const auto& specularBoxInfo = MaterialGenerator::GetMaterialRootNodeBox(MaterialGraphBoxes::Specular);
|
||||
auto specularBox = rootNode ? rootNode->GetBox(specularBoxInfo.ID) : nullptr;
|
||||
if (specularBox && specularBox->HasConnection())
|
||||
{
|
||||
auto& customCodeNode = graph.Nodes.AddOne();
|
||||
customCodeNode.ID = graph.Nodes.Count() + 1000;
|
||||
customCodeNode.Type = GRAPH_NODE_MAKE_TYPE(1, 8);
|
||||
customCodeNode.Boxes.Resize(2);
|
||||
customCodeNode.Boxes[0] = MaterialGraphBox(&customCodeNode, 0, VariantType::Float4); // Input0
|
||||
customCodeNode.Boxes[1] = MaterialGraphBox(&customCodeNode, 8, VariantType::Float4); // Output0
|
||||
customCodeNode.Values.Resize(1);
|
||||
customCodeNode.Values[0] = TEXT("// Convert old Specular value to a new range\nOutput0.x = min(Input0.x * 0.5f, 0.6f);");
|
||||
auto specularSourceBox = specularBox->Connections[0];
|
||||
specularBox->Connections.Clear();
|
||||
specularSourceBox->Connections.Clear();
|
||||
#define CONNECT(boxA, boxB) boxA->Connections.Add(boxB); boxB->Connections.Add(boxA)
|
||||
CONNECT(specularSourceBox, (&customCodeNode.Boxes[0])); // Specular -> Input0
|
||||
CONNECT((&customCodeNode.Boxes[1]), specularBox); // Output0 -> Specular
|
||||
#undef CONNECT
|
||||
}
|
||||
}
|
||||
if (!graph.Save(&writeStream, true))
|
||||
{
|
||||
surfaceChunk->Data.Copy(ToSpan(writeStream));
|
||||
ContentDeprecated::Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
/// <summary>
|
||||
/// Current materials shader version.
|
||||
/// </summary>
|
||||
#define MATERIAL_GRAPH_VERSION 176
|
||||
#define MATERIAL_GRAPH_VERSION 177
|
||||
|
||||
class Material;
|
||||
class GPUShader;
|
||||
|
||||
@@ -106,7 +106,7 @@ void MaterialGenerator::ProcessGroupMaterial(Box* box, Node* node, Value& value)
|
||||
Value values[OutputsMax];
|
||||
for (int32 i = 0; i < OutputsMax; i++)
|
||||
{
|
||||
const auto outputBox = node->GetBox(Output0BoxID + i);
|
||||
const auto outputBox = node->TryGetBox(Output0BoxID + i);
|
||||
if (outputBox && outputBox->HasConnection())
|
||||
{
|
||||
values[i] = writeLocal(VariantType::Float4, node);
|
||||
@@ -119,7 +119,7 @@ void MaterialGenerator::ProcessGroupMaterial(Box* box, Node* node, Value& value)
|
||||
for (int32 i = 0; i < InputsMax; i++)
|
||||
{
|
||||
auto inputName = TEXT("Input") + StringUtils::ToString(i);
|
||||
const auto inputBox = node->GetBox(Input0BoxID + i);
|
||||
const auto inputBox = node->TryGetBox(Input0BoxID + i);
|
||||
if (inputBox && inputBox->HasConnection())
|
||||
{
|
||||
auto inputValue = tryGetValue(inputBox, Value::Zero);
|
||||
@@ -131,7 +131,7 @@ void MaterialGenerator::ProcessGroupMaterial(Box* box, Node* node, Value& value)
|
||||
for (int32 i = 0; i < OutputsMax; i++)
|
||||
{
|
||||
auto outputName = TEXT("Output") + StringUtils::ToString(i);
|
||||
const auto outputBox = node->GetBox(Output0BoxID + i);
|
||||
const auto outputBox = node->TryGetBox(Output0BoxID + i);
|
||||
if (outputBox && outputBox->HasConnection())
|
||||
{
|
||||
code.Replace(*outputName, *values[i].Value, StringSearchCase::CaseSensitive);
|
||||
@@ -146,7 +146,7 @@ void MaterialGenerator::ProcessGroupMaterial(Box* box, Node* node, Value& value)
|
||||
// Link output values to boxes
|
||||
for (int32 i = 0; i < OutputsMax; i++)
|
||||
{
|
||||
const auto outputBox = node->GetBox(Output0BoxID + i);
|
||||
const auto outputBox = node->TryGetBox(Output0BoxID + i);
|
||||
if (outputBox && outputBox->HasConnection())
|
||||
{
|
||||
outputBox->Cache = values[i];
|
||||
|
||||
@@ -58,6 +58,12 @@ float3 F_Schlick(float3 specularColor, float VoH)
|
||||
return saturate(50.0 * specularColor.g) * fc + (1 - fc) * specularColor;
|
||||
}
|
||||
|
||||
float3 F_Schlick(float3 f0, float3 f90, float VoH)
|
||||
{
|
||||
float fc = Pow5(1 - VoH);
|
||||
return f90 * fc + (1 - fc) * f0;
|
||||
}
|
||||
|
||||
#define REFLECTION_CAPTURE_NUM_MIPS 7
|
||||
#define REFLECTION_CAPTURE_ROUGHEST_MIP 1
|
||||
#define REFLECTION_CAPTURE_ROUGHNESS_MIP_SCALE 1.2
|
||||
|
||||
@@ -27,26 +27,28 @@ bool IsSubsurfaceMode(int shadingModel)
|
||||
return shadingModel == SHADING_MODEL_SUBSURFACE || shadingModel == SHADING_MODEL_FOLIAGE;
|
||||
}
|
||||
|
||||
float3 GetDiffuseColor(in float3 color, in float metalness)
|
||||
float3 GetDiffuseColor(float3 color, float metalness)
|
||||
{
|
||||
return color - color * metalness;
|
||||
return color * (1.0 - metalness);
|
||||
}
|
||||
|
||||
float3 GetSpecularColor(in float3 color, in float specular, in float metalness)
|
||||
// [https://google.github.io/filament/Filament.md.html]
|
||||
float3 GetSpecularColor(float3 color, float specular, float metalness)
|
||||
{
|
||||
return lerp(0.08 * specular.xxx, color.rgb, metalness.xxx);
|
||||
float dielectricF0 = 0.16 * specular * specular;
|
||||
return lerp(dielectricF0.xxx, color, metalness.xxx);
|
||||
}
|
||||
|
||||
// Calculate material diffuse color
|
||||
float3 GetDiffuseColor(in GBufferSample gBuffer)
|
||||
float3 GetDiffuseColor(GBufferSample gBuffer)
|
||||
{
|
||||
return gBuffer.Color - gBuffer.Color * gBuffer.Metalness;
|
||||
return GetDiffuseColor(gBuffer.Color, gBuffer.Metalness);
|
||||
}
|
||||
|
||||
// Calculate material specular color
|
||||
float3 GetSpecularColor(in GBufferSample gBuffer)
|
||||
float3 GetSpecularColor(GBufferSample gBuffer)
|
||||
{
|
||||
return lerp(0.08 * gBuffer.Specular.xxx, gBuffer.Color.rgb, gBuffer.Metalness.xxx);
|
||||
return GetSpecularColor(gBuffer.Color, gBuffer.Specular, gBuffer.Metalness);
|
||||
}
|
||||
|
||||
// Compact Normal Storage for Small G-Buffers
|
||||
|
||||
@@ -31,6 +31,7 @@ LightSample StandardShading(GBufferSample gBuffer, float energy, float3 L, float
|
||||
float3 F = F_Schlick(specularColor, VoH);
|
||||
float D = D_GGX(gBuffer.Roughness, NoH) * energy;
|
||||
float Vis = Vis_SmithJointApprox(gBuffer.Roughness, NoV, NoL);
|
||||
// TODO: apply energy compensation to specular (1.0 + specularColor * (1.0 / PreIntegratedGF.y - 1.0))
|
||||
lighting.Specular = (D * Vis) * F;
|
||||
#endif
|
||||
lighting.Transmission = 0;
|
||||
|
||||
@@ -78,8 +78,6 @@ float4 PS_CombinePass(Quad_VS2PS input) : SV_Target0
|
||||
|
||||
// Calculate specular color
|
||||
float3 specularColor = GetSpecularColor(gBuffer);
|
||||
if (gBuffer.Metalness < 0.001)
|
||||
specularColor = 0.04f * gBuffer.Specular;
|
||||
|
||||
// Calculate reflecion color
|
||||
float3 V = normalize(gBufferData.ViewPos - gBuffer.WorldPos);
|
||||
|
||||
@@ -83,8 +83,6 @@ float4 PS_CombinePass(Quad_VS2PS input) : SV_Target0
|
||||
|
||||
// Calculate specular color
|
||||
float3 specularColor = GetSpecularColor(gBuffer);
|
||||
if (gBuffer.Metalness < 0.001)
|
||||
specularColor = 0.04f * gBuffer.Specular;
|
||||
|
||||
// Calculate reflection color
|
||||
float3 V = normalize(gBufferData.ViewPos - gBuffer.WorldPos);
|
||||
|
||||
Reference in New Issue
Block a user