Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 70 additions & 3 deletions Runtime/Scripts/GltfImport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1708,6 +1708,70 @@ void SetTextureGamma(TextureInfoBase textureInfo)
}
}

// Compute per-texture channel mask based on material slot references.
var textureChannels = new byte[Root.Textures.Count];
if (Root.Materials != null)
{
const byte R = 1, G = 2, B = 4, A = 8, RG = R | G, GB = G | B, RGB = R | G | B;
void AddChannels(TextureInfoBase textureInfo, byte mask)
{
if (textureInfo is { index: >= 0 } && textureInfo.index < Root.Textures.Count)
textureChannels[textureInfo.index] |= mask;
}

foreach (var material in Root.Materials)
{
if (material.PbrMetallicRoughness != null)
{
// baseColor: RGB, plus A unless the material is fully opaque.
var baseColorMask = RGB;
if (material.GetAlphaMode() != MaterialBase.AlphaMode.Opaque)
baseColorMask |= A;
AddChannels(material.PbrMetallicRoughness.BaseColorTexture, baseColorMask);

// metallic-roughness: roughness=G, metallic=B (occlusion adds R when packed/ORM).
AddChannels(material.PbrMetallicRoughness.MetallicRoughnessTexture, GB);
}
AddChannels(material.OcclusionTexture, R);
AddChannels(material.NormalTexture, RG);
AddChannels(material.EmissiveTexture, RGB);

var ext = material.Extensions;
if (ext != null)
{
if (ext.KHR_materials_pbrSpecularGlossiness != null)
{
AddChannels(ext.KHR_materials_pbrSpecularGlossiness.diffuseTexture, RGB);
AddChannels(ext.KHR_materials_pbrSpecularGlossiness.specularGlossinessTexture, RGB);
}
if (ext.KHR_materials_transmission != null)
{
// KHR_materials_transmission: transmission factor in R.
AddChannels(ext.KHR_materials_transmission.transmissionTexture, R);
}
if (ext.KHR_materials_clearcoat != null)
{
// KHR_materials_clearcoat: clearcoat=R, clearcoat roughness=G, plus a normal map.
AddChannels(ext.KHR_materials_clearcoat.clearcoatTexture, R);
AddChannels(ext.KHR_materials_clearcoat.clearcoatRoughnessTexture, G);
AddChannels(ext.KHR_materials_clearcoat.clearcoatNormalTexture, RG);
}
if (ext.KHR_materials_sheen != null)
{
// KHR_materials_sheen: sheen color=RGB, sheen roughness=A.
AddChannels(ext.KHR_materials_sheen.sheenColorTexture, RGB);
AddChannels(ext.KHR_materials_sheen.sheenRoughnessTexture, A);
}
if (ext.KHR_materials_specular != null)
{
// KHR_materials_specular: specular strength=A, specular color=RGB.
AddChannels(ext.KHR_materials_specular.specularTexture, A);
AddChannels(ext.KHR_materials_specular.specularColorTexture, RGB);
}
}
}
}

#if !UNITY_VISIONOS
HashSet<int> readableTextureIndices = null;
#endif
Expand Down Expand Up @@ -1820,7 +1884,8 @@ void SetTextureGamma(TextureInfoBase textureInfo)
m_Settings.GenerateMipMaps,
cancellationToken,
loader,
DeferAgent
DeferAgent,
textureChannels[textureIndex]
);
continue;
}
Expand Down Expand Up @@ -1848,7 +1913,8 @@ void SetTextureGamma(TextureInfoBase textureInfo)
m_Settings.GenerateMipMaps,
cancellationToken,
defaultLoader,
DeferAgent
DeferAgent,
textureChannels[textureIndex]
);
return true;
}
Expand Down Expand Up @@ -1907,7 +1973,8 @@ void SetTextureGamma(TextureInfoBase textureInfo)
m_Settings.GenerateMipMaps,
GetImageDataAsync(img, cancellationToken),
m_Addons,
cancellationToken
cancellationToken,
textureChannels[textureIndex]
);
}
}
Expand Down
22 changes: 22 additions & 0 deletions Runtime/Scripts/ITextureImageLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,28 @@ Task<ImageResult> LoadImage(
CancellationToken cancellationToken
);

/// <summary>
/// Channel-aware variant of <see cref="LoadImage(NativeArray{byte}.ReadOnly,bool,bool,bool,CancellationToken)"/>.
/// <paramref name="channelMask"/> is a bitmask of the channels the referencing materials actually consume, so a
/// loader can pick the most efficient format. The default implementation ignores the mask and forwards to the
/// channel-unaware overload, so existing loaders keep working unchanged.
/// </summary>
/// <param name="data">Raw, compressed image data.</param>
/// <param name="linear">If true, the texture being created is in linear space. If false, it is in sRGB space.</param>
/// <param name="readable">If true, the resulting texture should remain readable (<see cref="UnityEngine.Texture2D.isReadable"/>).</param>
/// <param name="generateMipMaps">If true, mipmap levels should get generated.</param>
/// <param name="cancellationToken">Token to submit cancellation requests. The default value is None.</param>
/// <param name="channelMask">Bitmask of channels consumed by referencing materials (bit0=R..bit3=A).</param>
/// <returns>An image texture result</returns>
Task<ImageResult> LoadImage(
NativeArray<byte>.ReadOnly data,
bool linear,
bool readable,
bool generateMipMaps,
CancellationToken cancellationToken,
int channelMask
) => LoadImage(data, linear, readable, generateMipMaps, cancellationToken);

/// <summary>
/// Determines if this loader can load the given texture, and if so, returns the corresponding image index.
/// The typical use-case is a glTF texture extension that adds support for a new image format,
Expand Down
11 changes: 7 additions & 4 deletions Runtime/Scripts/ImageImport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ internal static async Task<ImageResult> LoadImageAsync(
bool generateMipMaps,
Task<IReadOnlyDisposableData> dataTask,
ImportAddonInstanceCollection addons,
CancellationToken cancellationToken
CancellationToken cancellationToken,
int channelMask = 0xF
)
{
using var data = await dataTask;
Expand All @@ -46,7 +47,8 @@ CancellationToken cancellationToken
linear,
readable,
generateMipMaps,
cancellationToken);
cancellationToken,
channelMask);
if (task != null)
{
return await task;
Expand Down Expand Up @@ -99,7 +101,8 @@ internal static async Task<ImageResult> LoadImageAsync(
bool generateMipMaps,
CancellationToken cancellationToken,
ITextureImageLoader loader,
IDeferAgent deferAgent
IDeferAgent deferAgent,
int channelMask = 0xF
)
{
using var data = await dataTask;
Expand All @@ -112,7 +115,7 @@ IDeferAgent deferAgent
cancellationToken.ThrowIfCancellationRequestedWithTracking();
await Task.Yield();
}
return await loader.LoadImage(data.Data, linear, readable, generateMipMaps, cancellationToken);
return await loader.LoadImage(data.Data, linear, readable, generateMipMaps, cancellationToken, channelMask);
}

internal static async Task<IReadOnlyDisposableData> LoadDataAsync(
Expand Down