Files
AR-Menu/Library/PackageCache/com.unity.cloud.gltfast@db5a82ec0b47/Runtime/Scripts/Export/OrmImageExport.cs
2025-11-30 08:35:03 +02:00

335 lines
11 KiB
C#

// SPDX-FileCopyrightText: 2023 Unity Technologies and the glTFast authors
// SPDX-License-Identifier: Apache-2.0
using System;
using System.IO;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Assertions;
#if UNITY_2022_1_OR_NEWER
using UnityEngine.Experimental.Rendering;
#endif
using Object = UnityEngine.Object;
namespace GLTFast.Export
{
/// <summary>
/// Exports a glTF ORM (occlusion/roughness/metallic) image map
/// </summary>
class OrmImageExport : ImageExport
{
static Material s_MetalGlossBlitMaterial;
static Material s_OcclusionBlitMaterial;
static Material s_GlossBlitMaterial;
readonly Texture2D m_OccTexture;
readonly Texture2D m_SmoothnessTexture;
/// <summary>
/// Default constructor
/// </summary>
/// <param name="metalGlossTexture">Metal/Gloss texture, as used by Unity Lit/Standard materials</param>
/// <param name="occlusionTexture">Occlusion texture, as used by Unity Lit/Standard materials</param>
/// <param name="smoothnessTexture">Smoothness texture, as used by Unity Lit/Standard materials</param>
/// <param name="imageFormat">Export image format</param>
public OrmImageExport(
Texture2D metalGlossTexture = null,
Texture2D occlusionTexture = null,
Texture2D smoothnessTexture = null,
ImageFormat imageFormat = ImageFormat.Unknown)
: base(metalGlossTexture, imageFormat)
{
m_OccTexture = occlusionTexture;
m_SmoothnessTexture = smoothnessTexture;
}
/// <inheritdoc />
public override string FileName
{
get
{
if (m_Texture != null) return base.FileName;
if (m_OccTexture != null && !string.IsNullOrEmpty(m_OccTexture.name))
{
return $"{m_OccTexture.name}.{FileExtension}";
}
if (m_SmoothnessTexture != null && !string.IsNullOrEmpty(m_SmoothnessTexture.name))
{
return $"{m_SmoothnessTexture.name}ORM.{FileExtension}";
}
return $"ORM.{FileExtension}";
}
}
/// <inheritdoc />
protected override ImageFormat ImageFormat => m_ImageFormat != ImageFormat.Unknown ? m_ImageFormat : ImageFormat.Jpg;
/// <inheritdoc />
public override FilterMode FilterMode
{
get
{
if (m_Texture != null)
{
return m_Texture.filterMode;
}
if (m_OccTexture != null)
{
return m_OccTexture.filterMode;
}
if (m_SmoothnessTexture != null)
{
return m_SmoothnessTexture.filterMode;
}
return FilterMode.Bilinear;
}
}
/// <inheritdoc />
public override TextureWrapMode WrapModeU
{
get
{
if (m_Texture != null)
{
return m_Texture.wrapModeU;
}
if (m_OccTexture != null)
{
return m_OccTexture.wrapModeU;
}
if (m_SmoothnessTexture != null)
{
return m_SmoothnessTexture.wrapModeU;
}
return TextureWrapMode.Repeat;
}
}
/// <inheritdoc />
public override TextureWrapMode WrapModeV
{
get
{
if (m_Texture != null)
{
return m_Texture.wrapModeV;
}
if (m_OccTexture != null)
{
return m_OccTexture.wrapModeV;
}
if (m_SmoothnessTexture != null)
{
return m_SmoothnessTexture.wrapModeV;
}
return TextureWrapMode.Repeat;
}
}
/// <summary>
/// True if occlusion texture was set
/// </summary>
public bool HasOcclusion => m_OccTexture != null;
static Material GetMetalGlossBlitMaterial()
{
if (s_MetalGlossBlitMaterial == null)
{
s_MetalGlossBlitMaterial = LoadBlitMaterial("glTFExportMetalGloss");
}
return s_MetalGlossBlitMaterial;
}
static Material GetOcclusionBlitMaterial()
{
if (s_OcclusionBlitMaterial == null)
{
s_OcclusionBlitMaterial = LoadBlitMaterial("glTFExportOcclusion");
}
return s_OcclusionBlitMaterial;
}
static Material GetGlossBlitMaterial()
{
if (s_GlossBlitMaterial == null)
{
s_GlossBlitMaterial = LoadBlitMaterial("glTFExportSmoothness");
}
return s_GlossBlitMaterial;
}
/// <inheritdoc />
public override bool Write(string filePath, bool overwrite)
{
if (GenerateTexture(out var imageData))
{
File.WriteAllBytes(filePath, imageData);
return true;
}
return false;
}
/// <inheritdoc />
protected override bool GenerateTexture(out byte[] imageData)
{
if (m_Texture != null || m_OccTexture != null || m_SmoothnessTexture != null)
{
imageData = EncodeOrmTexture(m_Texture, m_OccTexture, m_SmoothnessTexture, ImageFormat, JpgQuality);
return true;
}
imageData = null;
return false;
}
/// <summary>
/// Encodes ORM texture
/// </summary>
/// <param name="metalGlossTexture">Metal/Gloss texture</param>
/// <param name="occlusionTexture">Occlusion texture</param>
/// <param name="smoothnessTexture">Smoothness texture</param>
/// <param name="format">Export image format</param>
/// <param name="jpgQuality">[1-100] quality for JPG images</param>
/// <returns></returns>
static byte[] EncodeOrmTexture(
Texture2D metalGlossTexture,
Texture2D occlusionTexture,
Texture2D smoothnessTexture,
ImageFormat format,
int jpgQuality
)
{
#if UNITY_IMAGECONVERSION
Assert.IsTrue(metalGlossTexture!=null || occlusionTexture!=null || smoothnessTexture!=null);
var blitMaterial = GetMetalGlossBlitMaterial();
var width = int.MinValue;
var height = int.MinValue;
if (metalGlossTexture != null) {
width = math.max( width, metalGlossTexture.width);
height = math.max(height, metalGlossTexture.height);
}
if (occlusionTexture != null) {
width = math.max( width, occlusionTexture.width);
height = math.max(height, occlusionTexture.height);
}
if (smoothnessTexture != null) {
width = math.max( width, smoothnessTexture.width);
height = math.max(height, smoothnessTexture.height);
}
var destRenderTexture = RenderTexture.GetTemporary(
width,
height,
0,
RenderTextureFormat.ARGB32,
RenderTextureReadWrite.Linear,
1,
RenderTextureMemoryless.Depth
);
if (metalGlossTexture == null) {
var rt = RenderTexture.active;
RenderTexture.active = destRenderTexture;
GL.Clear(true, true, Color.white);
RenderTexture.active = rt;
}
else {
Graphics.Blit(metalGlossTexture, destRenderTexture, blitMaterial);
}
if (occlusionTexture != null) {
blitMaterial = GetOcclusionBlitMaterial();
Graphics.Blit(occlusionTexture, destRenderTexture, blitMaterial);
}
if (smoothnessTexture != null) {
blitMaterial = GetGlossBlitMaterial();
Graphics.Blit(smoothnessTexture, destRenderTexture, blitMaterial);
}
var exportTexture = new Texture2D(
width,
height,
#if UNITY_2023_2_OR_NEWER
// ~20 times faster texture construction
SystemInfo.IsFormatSupported(GraphicsFormat.R8G8B8_UNorm, GraphicsFormatUsage.Sample)
? GraphicsFormat.R8G8B8_UNorm
: GraphicsFormat.R8G8B8A8_UNorm,
TextureCreationFlags.DontInitializePixels | TextureCreationFlags.DontUploadUponCreate
#elif UNITY_2022_1_OR_NEWER
// ~20 times faster texture construction
SystemInfo.IsFormatSupported(GraphicsFormat.R8G8B8_UNorm, FormatUsage.Sample)
? GraphicsFormat.R8G8B8_UNorm
: GraphicsFormat.R8G8B8A8_UNorm,
TextureCreationFlags.DontInitializePixels | TextureCreationFlags.DontUploadUponCreate
#else
TextureFormat.RGB24,
false,
true
#endif
);
exportTexture.ReadPixels(new Rect(0, 0, destRenderTexture.width, destRenderTexture.height), 0, 0);
RenderTexture.ReleaseTemporary(destRenderTexture);
exportTexture.Apply();
var imageData = format == ImageFormat.Png
? exportTexture.EncodeToPNG()
: exportTexture.EncodeToJPG(jpgQuality);
// Release temporary texture
#if UNITY_EDITOR
Object.DestroyImmediate(exportTexture);
#else
Object.Destroy(exportTexture);
#endif
return imageData;
#else
return null;
#endif
}
/// <inheritdoc />
public override int GetHashCode()
{
var hash = 14;
if (m_Texture != null)
{
hash = hash * 7 + m_Texture.GetHashCode();
}
if (m_OccTexture != null)
{
hash = hash * 7 + m_OccTexture.GetHashCode();
}
if (m_SmoothnessTexture != null)
{
hash = hash * 7 + m_SmoothnessTexture.GetHashCode();
}
return hash;
}
/// <inheritdoc />
public override bool Equals(object obj)
{
//Check for null and compare run-time types.
if (obj == null || GetType() != obj.GetType())
{
return false;
}
return Equals((OrmImageExport)obj);
}
bool Equals(OrmImageExport other)
{
return m_Texture == other.m_Texture
&& m_OccTexture == other.m_OccTexture
&& m_SmoothnessTexture == other.m_SmoothnessTexture;
}
}
}