// SPDX-FileCopyrightText: 2023 Unity Technologies and the Draco for Unity authors
// SPDX-License-Identifier: Apache-2.0
using UnityEngine;
namespace Draco.Encode
{
///
/// Quantization settings.
///
public readonly struct QuantizationSettings
{
// ReSharper disable MemberCanBePrivate.Global
/// Minimum quantization bits.
public const int minQuantization = 1;
/// Maximum quantization bits.
public const int maxQuantization = 30;
// ReSharper restore MemberCanBePrivate.Global
const int k_DefaultPositionQuantization = 14;
const int k_DefaultNormalQuantization = 10;
const int k_DefaultTexCoordQuantization = 12;
const int k_DefaultColorQuantization = 8;
const int k_DefaultGenericQuantization = 12;
///
/// Default quantization settings, used whenever no settings are provided.
///
public static readonly QuantizationSettings Default = new QuantizationSettings(
positionQuantization: k_DefaultPositionQuantization,
normalQuantization: k_DefaultNormalQuantization,
texCoordQuantization: k_DefaultTexCoordQuantization,
colorQuantization: k_DefaultColorQuantization
);
///
/// Vertex position quantization.
///
public readonly int positionQuantization;
///
/// Normal quantization.
///
public readonly int normalQuantization;
///
/// Texture coordinate quantization.
///
public readonly int texCoordQuantization;
///
/// Color quantization.
///
public readonly int colorQuantization;
///
/// Default quantization for generic attributes. Unused at the moment.
///
public static int genericQuantization => k_DefaultGenericQuantization;
///
/// Constructs quantization settings.
/// Defaults are applied for normal, texture coordinate and color quantization.
///
/// Initializes
public QuantizationSettings(int positionQuantization)
{
this.positionQuantization = Mathf.Clamp(positionQuantization, minQuantization, maxQuantization);
normalQuantization = k_DefaultNormalQuantization;
texCoordQuantization = k_DefaultTexCoordQuantization;
colorQuantization = k_DefaultColorQuantization;
}
///
/// Constructs quantization settings.
///
/// Initializes
/// Initializes
/// Initializes
/// Initializes
public QuantizationSettings(
int positionQuantization,
int normalQuantization,
int texCoordQuantization,
int colorQuantization
)
{
this.positionQuantization = Mathf.Clamp(positionQuantization, minQuantization, maxQuantization);
this.normalQuantization = Mathf.Clamp(normalQuantization, minQuantization, maxQuantization);
this.texCoordQuantization = Mathf.Clamp(texCoordQuantization, minQuantization, maxQuantization);
this.colorQuantization = Mathf.Clamp(colorQuantization, minQuantization, maxQuantization);
}
///
/// True if all quantization parameters have valid values within minimum
/// and maximum.
///
public bool IsValid =>
positionQuantization >= minQuantization && positionQuantization <= maxQuantization
&& normalQuantization >= minQuantization && normalQuantization <= maxQuantization
&& texCoordQuantization >= minQuantization && texCoordQuantization <= maxQuantization
&& colorQuantization >= minQuantization && colorQuantization <= maxQuantization;
///
public override string ToString()
{
return $"QuantizationSettings(pos:{positionQuantization},normal:{normalQuantization},uv:{texCoordQuantization},color:{colorQuantization})";
}
///
/// Constructs quantization settings.
/// The position quantization value is based on the mesh's bounds, its scale in the world and the desired
/// precision in world units. The rest will be default values.
///
/// Size of the mesh
/// World scale of the object
/// Desired minimum precision in world units
/// Quantization settings
public static QuantizationSettings FromWorldSize(
Bounds meshBounds,
Vector3 worldScale,
float precision
)
{
return new QuantizationSettings(
positionQuantization: GetIdealQuantization(worldScale, meshBounds, precision),
normalQuantization: k_DefaultNormalQuantization,
texCoordQuantization: k_DefaultTexCoordQuantization,
colorQuantization: k_DefaultColorQuantization
);
}
///
/// Constructs quantization settings.
/// The position quantization value is based on the mesh's bounds, its scale in the world and the desired
/// precision in world units.
///
/// Size of the mesh
/// World scale of the object
/// Desired minimum precision in world units
/// Initializes
/// Initializes
/// Initializes
/// QuantizationSettings settings
public static QuantizationSettings FromWorldSize(
Bounds meshBounds,
Vector3 worldScale,
float precision,
int normalQuantization,
int texCoordQuantization,
int colorQuantization
)
{
return new QuantizationSettings(
positionQuantization: GetIdealQuantization(worldScale, meshBounds, precision),
normalQuantization: normalQuantization,
texCoordQuantization: texCoordQuantization,
colorQuantization: colorQuantization
);
}
///
/// Calculates the ideal position quantization value based on an object's world scale, bounds and the desired
/// precision in world units.
///
/// World scale of the object
/// Desired minimum precision in world units
/// Size of the mesh
/// Ideal quantization in bits
static int GetIdealQuantization(Vector3 worldScale, Bounds bounds, float precision)
{
var scale = new Vector3(Mathf.Abs(worldScale.x), Mathf.Abs(worldScale.y), Mathf.Abs(worldScale.z));
var maxSize = Mathf.Max(
bounds.extents.x * scale.x,
bounds.extents.y * scale.y,
bounds.extents.z * scale.z
) * 2;
return GetIdealQuantization(maxSize, precision);
}
///
/// Calculates the ideal quantization value based on the largest dimension and desired precision
///
/// Length of the largest dimension (width/depth/height)
/// Desired minimum precision in world units
/// Ideal quantization in bits
static int GetIdealQuantization(float largestDimension, float precision)
{
var value = Mathf.RoundToInt(largestDimension / precision);
var mostSignificantBit = -1;
while (value > 0)
{
mostSignificantBit++;
value >>= 1;
}
return Mathf.Clamp(mostSignificantBit, minQuantization, maxQuantization);
}
}
}