Add MaterialTextureMipBias to control texture mip bias in materials for better frame upscaling
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
// Version: @0
|
||||
|
||||
#define MATERIAL 1
|
||||
#define MaterialTextureMipBias 0.0f
|
||||
@3
|
||||
#include "./Flax/Common.hlsl"
|
||||
#include "./Flax/MaterialCommon.hlsl"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Version: @0
|
||||
|
||||
#define MATERIAL 1
|
||||
#define MaterialTextureMipBias 0.0f
|
||||
@3
|
||||
|
||||
#include "./Flax/Common.hlsl"
|
||||
|
||||
@@ -316,7 +316,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
DefaultValues = new object[]
|
||||
{
|
||||
(int)CommonSamplerType.LinearClamp, // Sampler
|
||||
-1.0f, // Level
|
||||
-1.0f, // Level (-1 when unused)
|
||||
0, // Texture Group
|
||||
},
|
||||
Elements = new[]
|
||||
@@ -476,7 +476,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
DefaultValues = new object[]
|
||||
{
|
||||
(int)CommonSamplerType.LinearWrap, // Sampler
|
||||
-1.0f, // Level
|
||||
-1.0f, // Level (-1 when unused)
|
||||
0, // Texture Group
|
||||
},
|
||||
Elements = new[]
|
||||
|
||||
@@ -37,7 +37,8 @@ GPU_CB_STRUCT(MaterialShaderDataPerView {
|
||||
Float4 TemporalAAJitter;
|
||||
Float3 LargeWorldsChunkIndex;
|
||||
float LargeWorldsChunkSize;
|
||||
Float3 ViewPadding0;
|
||||
float MaterialTextureMipBias;
|
||||
float ViewPadding0;
|
||||
float TestValue;
|
||||
float ScaledTimeParam;
|
||||
});
|
||||
@@ -87,6 +88,7 @@ void IMaterial::BindParameters::BindViewData()
|
||||
cb.TemporalAAJitter = view.TemporalAAJitter;
|
||||
cb.LargeWorldsChunkIndex = LargeWorlds::Enable ? (Float3)Int3(view.Origin / LargeWorlds::ChunkSize) : Float3::Zero;
|
||||
cb.LargeWorldsChunkSize = LargeWorlds::ChunkSize;
|
||||
cb.MaterialTextureMipBias = RenderContext.List->Setup.MaterialTextureMipBias;
|
||||
cb.TestValue = Graphics::TestValue;
|
||||
|
||||
// Update constants
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
/// <summary>
|
||||
/// Current materials shader version.
|
||||
/// </summary>
|
||||
#define MATERIAL_GRAPH_VERSION 185
|
||||
#define MATERIAL_GRAPH_VERSION 186
|
||||
|
||||
class Material;
|
||||
class GPUShader;
|
||||
|
||||
@@ -286,6 +286,11 @@ public:
|
||||
/// </summary>
|
||||
API_FIELD() float RenderScale = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// The texture mip level bias for materials. Positive values make textures appear blurrier; negative values sharpen.
|
||||
/// </summary>
|
||||
API_FIELD() float MaterialTextureMipBias = 0.0f;
|
||||
|
||||
/// <summary>
|
||||
/// The image resolution upscale location within rendering pipeline. Unused if RenderingPercentage is 1.
|
||||
/// </summary>
|
||||
|
||||
@@ -11,6 +11,7 @@ struct FLAXENGINE_API RenderSetup
|
||||
{
|
||||
RenderingUpscaleLocation UpscaleLocation = RenderingUpscaleLocation::DuringAntiAliasing;
|
||||
float RenderScale = 1.0f;
|
||||
float MaterialTextureMipBias = 0.0f;
|
||||
bool UseShadows = false;
|
||||
bool UseMotionVectors = false;
|
||||
bool UseTemporalAAJitter = false;
|
||||
|
||||
@@ -426,6 +426,11 @@ PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
||||
setup.UseGlobalSurfaceAtlas;
|
||||
setup.UseVolumetricFog = (renderContext.View.Flags & ViewFlags::Fog) != ViewFlags::None;
|
||||
|
||||
// Calculate material texture mip bias
|
||||
setup.MaterialTextureMipBias = renderContext.Task->MaterialTextureMipBias;
|
||||
if (setup.RenderScale < 1.0f) // Increase textures sharpness when upscaling (eg. -1.0 bias when using 2x upscaling)
|
||||
setup.MaterialTextureMipBias += Math::Log2(setup.RenderScale);
|
||||
|
||||
// Disable TAA jitter in debug modes
|
||||
switch (renderContext.View.Mode)
|
||||
{
|
||||
|
||||
@@ -71,11 +71,13 @@ void MaterialGenerator::ProcessGroupParameters(Box* box, Node* node, Value& valu
|
||||
case MaterialParameterType::CubeTexture:
|
||||
case MaterialParameterType::NormalMap:
|
||||
case MaterialParameterType::Texture:
|
||||
sampleTexture(node, value, box, param, true);
|
||||
break;
|
||||
case MaterialParameterType::GPUTextureArray:
|
||||
case MaterialParameterType::GPUTextureCube:
|
||||
case MaterialParameterType::GPUTextureVolume:
|
||||
case MaterialParameterType::GPUTexture:
|
||||
sampleTexture(node, value, box, param);
|
||||
sampleTexture(node, value, box, param, false);
|
||||
break;
|
||||
default: CRASH;
|
||||
break;
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace
|
||||
};
|
||||
};
|
||||
|
||||
MaterialValue* MaterialGenerator::sampleTextureRaw(Node* caller, Value& value, Box* box, SerializedMaterialParam* texture)
|
||||
MaterialValue* MaterialGenerator::sampleTextureRaw(Node* caller, Value& value, Box* box, SerializedMaterialParam* texture, bool useGlobalMipBias)
|
||||
{
|
||||
ASSERT(texture && box);
|
||||
const auto parent = box->GetParent<ShaderGraphNode<>>();
|
||||
@@ -60,15 +60,27 @@ MaterialValue* MaterialGenerator::sampleTextureRaw(Node* caller, Value& value, B
|
||||
// Check if hasn't been sampled during that tree eating
|
||||
if (valueBox->Cache.IsInvalid())
|
||||
{
|
||||
bool canUseSample = CanUseSample(_treeType);
|
||||
bool useLevel = !CanUseSample(_treeType), useBias = false;
|
||||
String mipLevel = TEXT("0");
|
||||
const auto layer = GetRootLayer();
|
||||
if (layer && layer->Domain == MaterialDomain::Decal && _treeType == MaterialTreeType::PixelShader)
|
||||
{
|
||||
// Decals use computed mip level due to ddx/ddy being unreliable
|
||||
canUseSample = false;
|
||||
useLevel = true;
|
||||
mipLevel = String::Format(TEXT("CalculateTextureMipmap(input, {})"), texture->ShaderName);
|
||||
}
|
||||
if (useGlobalMipBias)
|
||||
{
|
||||
if (useLevel)
|
||||
{
|
||||
mipLevel += TEXT(" + MaterialTextureMipBias");
|
||||
}
|
||||
else
|
||||
{
|
||||
useBias = true;
|
||||
mipLevel = TEXT("MaterialTextureMipBias");
|
||||
}
|
||||
}
|
||||
|
||||
// Check if use custom UVs
|
||||
String uv;
|
||||
@@ -93,12 +105,8 @@ MaterialValue* MaterialGenerator::sampleTextureRaw(Node* caller, Value& value, B
|
||||
uv = use3dUVs ? TEXT("float3(input.TexCoord.xy, 0)") : TEXT("input.TexCoord.xy");
|
||||
}
|
||||
|
||||
// Select sampler
|
||||
// TODO: add option for texture groups and per texture options like wrap mode etc.
|
||||
// TODO: changing texture sampler option
|
||||
const Char* sampler = TEXT("SamplerLinearWrap");
|
||||
|
||||
// Sample texture
|
||||
const Char* sampler = TEXT("SamplerLinearWrap");
|
||||
if (texture->AsInteger == (int32)MaterialSceneTextures::SceneDepth)
|
||||
{
|
||||
// Sample depth buffer
|
||||
@@ -107,9 +115,8 @@ MaterialValue* MaterialGenerator::sampleTextureRaw(Node* caller, Value& value, B
|
||||
}
|
||||
else if (isNormalMap)
|
||||
{
|
||||
const Char* format = canUseSample ? TEXT("{0}.Sample({1}, {2}).xyz") : TEXT("{0}.SampleLevel({1}, {2}, {3}).xyz");
|
||||
|
||||
// Sample encoded normal map
|
||||
const Char* format = useLevel ? TEXT("{0}.SampleLevel({1}, {2}, {3}).xyz") : (useBias ? TEXT("{0}.SampleBias({1}, {2}, {3}).xyz") : TEXT("{0}.Sample({1}, {2}).xyz"));
|
||||
const String sampledValue = String::Format(format, texture->ShaderName, sampler, uv, mipLevel);
|
||||
const auto normalVector = writeLocal(VariantType::Float3, sampledValue, parent);
|
||||
|
||||
@@ -120,27 +127,8 @@ MaterialValue* MaterialGenerator::sampleTextureRaw(Node* caller, Value& value, B
|
||||
}
|
||||
else
|
||||
{
|
||||
// Select format string based on texture type
|
||||
const Char* format;
|
||||
/*if (isCubemap)
|
||||
{
|
||||
MISSING_CODE("sampling cube maps and 3d texture in material generator");
|
||||
//format = TEXT("SAMPLE_CUBEMAP({0}, {1})");
|
||||
}
|
||||
else*/
|
||||
{
|
||||
/*if (useCustomUVs)
|
||||
{
|
||||
createGradients(writer, parent);
|
||||
format = TEXT("SAMPLE_TEXTURE_GRAD({0}, {1}, {2}, {3})");
|
||||
}
|
||||
else*/
|
||||
{
|
||||
format = canUseSample ? TEXT("{0}.Sample({1}, {2})") : TEXT("{0}.SampleLevel({1}, {2}, {3})");
|
||||
}
|
||||
}
|
||||
|
||||
// Sample texture
|
||||
const Char* format = useLevel ? TEXT("{0}.SampleLevel({1}, {2}, {3})") : (useBias ? TEXT("{0}.SampleBias({1}, {2}, {3})") : TEXT("{0}.Sample({1}, {2})"));
|
||||
String sampledValue = String::Format(format, texture->ShaderName, sampler, uv, mipLevel);
|
||||
valueBox->Cache = writeLocal(VariantType::Float4, sampledValue, parent);
|
||||
}
|
||||
@@ -149,9 +137,9 @@ MaterialValue* MaterialGenerator::sampleTextureRaw(Node* caller, Value& value, B
|
||||
return &valueBox->Cache;
|
||||
}
|
||||
|
||||
void MaterialGenerator::sampleTexture(Node* caller, Value& value, Box* box, SerializedMaterialParam* texture)
|
||||
void MaterialGenerator::sampleTexture(Node* caller, Value& value, Box* box, SerializedMaterialParam* texture, bool useGlobalMipBias)
|
||||
{
|
||||
const auto sample = sampleTextureRaw(caller, value, box, texture);
|
||||
const auto sample = sampleTextureRaw(caller, value, box, texture, useGlobalMipBias);
|
||||
if (sample == nullptr)
|
||||
return;
|
||||
|
||||
@@ -202,16 +190,26 @@ void MaterialGenerator::ProcessGroupTextures(Box* box, Node* node, Value& value)
|
||||
{
|
||||
// Texture
|
||||
case 1:
|
||||
// Cube Texture
|
||||
case 3:
|
||||
// Normal Map
|
||||
case 4:
|
||||
{
|
||||
// Check if texture has been selected
|
||||
Guid textureId = (Guid)node->Values[0];
|
||||
if (textureId.IsValid())
|
||||
{
|
||||
// Get or create parameter for that texture
|
||||
auto param = findOrAddTexture(textureId);
|
||||
SerializedMaterialParam param;
|
||||
if (node->TypeID == 1) // Texture
|
||||
param = findOrAddTexture(textureId);
|
||||
else if (node->TypeID == 3) // Cube Texture
|
||||
param = findOrAddCubeTexture(textureId);
|
||||
else if (node->TypeID == 4) // Normal Map
|
||||
param = findOrAddNormalMap(textureId);
|
||||
|
||||
// Sample texture
|
||||
sampleTexture(node, value, box, ¶m);
|
||||
sampleTexture(node, value, box, ¶m, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -236,46 +234,6 @@ void MaterialGenerator::ProcessGroupTextures(Box* box, Node* node, Value& value)
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Cube Texture
|
||||
case 3:
|
||||
{
|
||||
// Check if texture has been selected
|
||||
Guid textureId = (Guid)node->Values[0];
|
||||
if (textureId.IsValid())
|
||||
{
|
||||
// Get or create parameter for that cube texture
|
||||
auto param = findOrAddCubeTexture(textureId);
|
||||
|
||||
// Sample texture
|
||||
sampleTexture(node, value, box, ¶m);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use default value
|
||||
value = Value::Zero;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Normal Map
|
||||
case 4:
|
||||
{
|
||||
// Check if texture has been selected
|
||||
Guid textureId = (Guid)node->Values[0];
|
||||
if (textureId.IsValid())
|
||||
{
|
||||
// Get or create parameter for that texture
|
||||
auto param = findOrAddNormalMap(textureId);
|
||||
|
||||
// Sample texture
|
||||
sampleTexture(node, value, box, ¶m);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use default value
|
||||
value = Value::Zero;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Parallax Occlusion Mapping
|
||||
case 5:
|
||||
{
|
||||
@@ -327,10 +285,11 @@ void MaterialGenerator::ProcessGroupTextures(Box* box, Node* node, Value& value)
|
||||
" float currRayHeight = 1.0;\n"
|
||||
" float lastSampledHeight = 1;\n"
|
||||
" int currSample = 0;\n"
|
||||
" float mipBiasDerivScale = pow(2, MaterialTextureMipBias);\n"
|
||||
|
||||
" while (currSample < (int)numSamples)\n"
|
||||
" {{\n"
|
||||
" float currSampledHeight = {1}.SampleGrad(SamplerLinearWrap, {10} + currOffset, {5}, {6}){7};\n"
|
||||
" float currSampledHeight = {1}.SampleGrad(SamplerLinearWrap, {10} + currOffset, {5} * mipBiasDerivScale, {6} * mipBiasDerivScale){7};\n"
|
||||
|
||||
" if (currSampledHeight > currRayHeight)\n"
|
||||
" {{\n"
|
||||
@@ -584,6 +543,7 @@ void MaterialGenerator::ProcessGroupTextures(Box* box, Node* node, Value& value)
|
||||
const bool isVolume = textureParam->Type == MaterialParameterType::GPUTextureVolume;
|
||||
const bool isNormalMap = textureParam->Type == MaterialParameterType::NormalMap;
|
||||
const bool use3dUVs = isCubemap || isArray || isVolume;
|
||||
const bool useGlobalMipBias = true; // Could be exposed as node option (separate check or within new set of CommonSamplerType values)
|
||||
uvs = Value::Cast(uvs, use3dUVs ? VariantType::Float3 : VariantType::Float2);
|
||||
|
||||
// Get other inputs
|
||||
@@ -613,7 +573,16 @@ void MaterialGenerator::ProcessGroupTextures(Box* box, Node* node, Value& value)
|
||||
{
|
||||
// Sample Texture
|
||||
const Char* format;
|
||||
if (useLevel || !canUseSample)
|
||||
if (useGlobalMipBias)
|
||||
{
|
||||
if (useLevel && useOffset)
|
||||
format = TEXT("{0}.SampleLevel({1}, {2}, {3} + MaterialTextureMipBias, {4})");
|
||||
else if (useOffset)
|
||||
format = TEXT("{0}.SampleBias({1}, {2}, MaterialTextureMipBias, {4})");
|
||||
else
|
||||
format = TEXT("{0}.SampleBias({1}, {2}, MaterialTextureMipBias)");
|
||||
}
|
||||
else if (useLevel || !canUseSample)
|
||||
{
|
||||
if (useOffset)
|
||||
format = TEXT("{0}.SampleLevel({1}, {2}, {3}, {4})");
|
||||
@@ -662,8 +631,9 @@ void MaterialGenerator::ProcessGroupTextures(Box* box, Node* node, Value& value)
|
||||
" uv1 = {0} + frac(sin(mul(float2x2(127.1, 311.7, 269.5, 183.3), vertex1)) * 43758.5453);\n"
|
||||
" uv2 = {0} + frac(sin(mul(float2x2(127.1, 311.7, 269.5, 183.3), vertex2)) * 43758.5453);\n"
|
||||
" uv3 = {0} + frac(sin(mul(float2x2(127.1, 311.7, 269.5, 183.3), vertex3)) * 43758.5453);\n"
|
||||
" float2 fdx = ddx({0});\n"
|
||||
" float2 fdy = ddy({0});\n"
|
||||
" float mipBiasDerivScale = pow(2, MaterialTextureMipBias);\n"
|
||||
" float2 fdx = ddx({0}) * mipBiasDerivScale;\n"
|
||||
" float2 fdy = ddy({0}) * mipBiasDerivScale;\n"
|
||||
" float4 tex1 = {1}.SampleGrad({2}, uv1, fdx, fdy, {4}) * weights.x;\n"
|
||||
" float4 tex2 = {1}.SampleGrad({2}, uv2, fdx, fdy, {4}) * weights.y;\n"
|
||||
" float4 tex3 = {1}.SampleGrad({2}, uv3, fdx, fdy, {4}) * weights.z;\n"
|
||||
|
||||
@@ -179,8 +179,8 @@ private:
|
||||
SerializedMaterialParam* findParam(const Guid& id, MaterialLayer* layer);
|
||||
MaterialGraphParameter* findGraphParam(const Guid& id);
|
||||
|
||||
MaterialValue* sampleTextureRaw(Node* caller, Value& value, Box* box, SerializedMaterialParam* texture);
|
||||
void sampleTexture(Node* caller, Value& value, Box* box, SerializedMaterialParam* texture);
|
||||
MaterialValue* sampleTextureRaw(Node* caller, Value& value, Box* box, SerializedMaterialParam* texture, bool useGlobalMipBias = false);
|
||||
void sampleTexture(Node* caller, Value& value, Box* box, SerializedMaterialParam* texture, bool useGlobalMipBias = false);
|
||||
void sampleSceneDepth(Node* caller, Value& value, Box* box);
|
||||
void linearizeSceneDepth(Node* caller, const Value& depth, Value& value);
|
||||
|
||||
|
||||
@@ -181,7 +181,8 @@ cbuffer ViewData : register(b1)
|
||||
float4 TemporalAAJitter;
|
||||
float3 LargeWorldsChunkIndex;
|
||||
float LargeWorldsChunkSize;
|
||||
float2 ViewPadding0;
|
||||
float MaterialTextureMipBias;
|
||||
float ViewPadding0;
|
||||
float TestValue;
|
||||
float ScaledTimeParam;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user