Add MaterialTextureMipBias to control texture mip bias in materials for better frame upscaling

This commit is contained in:
2026-08-16 14:30:53 +02:00
parent 1c25519d99
commit 708bdc7bcb
12 changed files with 74 additions and 86 deletions
@@ -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, &param);
sampleTexture(node, value, box, &param, 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, &param);
}
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, &param);
}
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"