// 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); } } }