【Unity】浮動小数点数の無限大の扱い方

こじゃらこじゃら

レイキャストの判定距離などの制限をなくしたい場合はどうすればいいの?

このはこのは

制限距離を無限大にすれば良いわ。

Unityで無限大の値を扱う方法の解説記事です。

無限大とは、どのような数よりも大きい事を意味します。逆にどのような数よりも小さい負の無限大もあります。

これらの無限大、負の無限大は、以下のようなコードでfloat型の値として取得できます。

// 正の無限大
var positiveInfinity = Mathf.Infinity;

// 負の無限大
var negativeInfinity = Mathf.NegativeInfinity;

無限大、負の無限大は、次のような比較計算に用いることで、無制限を表現できる場合があります。

Vector3 origin;
Vector3 direction;

・・・(中略)・・・

// 無限遠のレイキャスト判定でヒットするかどうか
var isHit = Physics.Raycast(origin, direction, Mathf.Infinity);

Unityでは、例えば次のAPIのパラメータに無限大を指定することで、無制限を表現することができます。

無限大の値を指定できる例
  • レイキャストの判定距離
  • SmoothDamp関数の最大の速さ
  • Clamp関数の上限・下限

一方で、無限大を指定することで計算結果が意図しないものになるなど、不都合が起こる場合もあるので、使用には十分注意する必要があります。 [1]

また、無限大を表現できるのは、float型、double型などの浮動小数点数に限られ、int型などの整数型では表現できません。

本記事では、このような注意点を含め、Unityで正の無限大、負の無限大を扱う方法を解説します。また、本記事で扱う解説はUnityでC#言語を扱う場合を想定しており、それ以外は対象外のため予めご了承ください。

動作環境
  • Unity 2022.1.5f1

スポンサーリンク

無限大の値をスクリプトから使用する

正の無限大はMathf.Infinityプロパティ、負の無限大はMathf.NegativeInfinityプロパティから得られます。

// 正の無限大
var positiveInfinity = Mathf.Infinity;

// 負の無限大
var negativeInfinity = Mathf.NegativeInfinity;

これらのプロパティは、それぞれ.NETのfloat.PositiveInfinityプロパティfloat.NegativeInfinityプロパティをラップしたものです。 [2]

そのため、以下のようなコードでも同様の結果が得られます。

// 正の無限大
var positiveInfinity = float.PositiveInfinity;

// 負の無限大
var negativeInfinity = float.NegativeInfinity;

無限大を文字列に変換した場合

正の無限大はInfinity、負の無限大は-Infinityという文字列になります。

以下、無限大をコンソールログ出力するサンプルスクリプトです。

PrintInfinityExample.cs
using UnityEngine;

public class PrintInfinityExample : MonoBehaviour
{
    private void Start()
    {
        // 正の無限大をログ出力
        Debug.Log($"Mathf.Infinity = {Mathf.Infinity}");

        // 負の無限大をログ出力
        Debug.Log($"Mathf.NegativeInfinity = {Mathf.NegativeInfinity}");
    }
}

上記スクリプトをPrintInfinityExample.csという名前で保存し、適当なゲームオブジェクトにアタッチすると機能するようになります。

実行結果

期待通りの出力が得られることを確認できました。

インスペクターから無限大を指定する

Unityエディタのインスペクターウィンドウから正の無限大、負の無限大を指定することもできます。

正の無限大はInfinity、負の無限大は-Infinityと入力します。

無限大の活用例

ここまで無限大の基本的な使い方について解説しました。

実際の活用例についてもいくつか紹介します。

レイキャストの距離制限解除

レイとコライダーとの交差判定にPhysics.Raycastメソッドを使用する場合、レイの最大距離を引数に指定できるようになっています。

public static bool Raycast(
    Vector3 origin,
    Vector3 direction,
    float maxDistance = Mathf.Infinity,
    int layerMask = DefaultRaycastLayers,
    QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.UseGlobal
);

実は、引数が表略された場合は、正の無限大Mathf.Infinityが指定されるようになっています。

明示的にMathf.Infinityを指定しても同様の挙動を実現できます。

以下、距離制限を解除してレイキャスト判定を行うサンプルスクリプトです。

RaycastExample.cs
using UnityEngine;

public class RaycastExample : MonoBehaviour
{
    private void Update()
    {
        var origin = transform.position;
        var direction = transform.forward;

        // 無限遠でレイキャスト判定する
        var isHit = Physics.Raycast(origin, direction, Mathf.Infinity);
        
        // 判定結果をログ出力
        Debug.Log($"isHit = {isHit}");
    }
}

上記スクリプトをRaycastExample.csという名前で保存し、適当なゲームオブジェクトにアタッチすると機能するようになります。

実行結果

どんなに遠くに離れていても、レイとコライダーが交差した場合はヒットとなります。

SmoothDamp関数の速度上限解除

目標の値に滑らかに追従させる(一致させる)ような値を計算するSmoothDamp系のメソッドでは、上限の速さを指定できます。

例えば、Vector3.SmoothDampメソッドの形式は次のようになっています。

public static Vector3 SmoothDamp(
    Vector3 current,
    Vector3 target,
    ref Vector3 currentVelocity,
    float smoothTime,
    float maxSpeed = Mathf.Infinity,
    float deltaTime = Time.deltaTime
);

このメソッドも上限の速さの引数maxSpeedが省略された場合はMathf.Infinityが指定されるようになっています。

先の例と同様、明示的にMathf.Infinityをしても同じ挙動となります。

以下、速さ制限なしでターゲットに追従させるスクリプトの例です。

SmoothDampExample.cs
using UnityEngine;

public class SmoothDampExample : MonoBehaviour
{
    // 追従対象
    [SerializeField] private Transform _target;

    private Vector3 _currentVelocity;

    private void Update()
    {
        // 速度制限なしでターゲットに追従
        transform.position = Vector3.SmoothDamp(
            transform.position,
            _target.position,
            ref _currentVelocity,
            0.1f,
            Mathf.Infinity
        );
    }
}

SmoothDampExample.csという名前で保存し、適当なゲームオブジェクトにアタッチし、Targetに追従対象のオブジェクトを指定すると機能するようになります。

実行結果

速度制限なしに追従することが確認できました。

SmoothDamp関数の使い方については、以下記事でも解説しています。

Clamp関数の制限解除

Mathf.Clampメソッドは、上限と下限の間に閉じ込めた値を返します。

どちらか一方のみに制限したい場合、無限大を指定することで実現できます。

以下、上限、下限を無制限にしたClampを行う例です。

ClampExample.cs
using UnityEngine;

public class ClampExample : MonoBehaviour
{
    // 入力値
    [SerializeField] private float _inputValue;

    // 下限
    [SerializeField] private float _min = -1;

    // 上限
    [SerializeField] private float _max = 1;

    private void Update()
    {
        // 下限のみ指定
        var clampMinOnly = Mathf.Clamp(_inputValue, _min, Mathf.Infinity);
        // 上限のみ指定
        var clampMaxOnly = Mathf.Clamp(_inputValue, Mathf.NegativeInfinity, _max);

        // 結果出力
        Debug.Log($"下限のみ指定 : {clampMinOnly}, 上限のみ指定 : {clampMaxOnly}");
    }
}

上記スクリプトをClampExample.csという名前で保存し、適当なゲームオブジェクトにアタッチすると機能します。

実行結果

片方に限定して値が制限されていることが確認できます。

無限大の内部表現について

C#言語のfloat型は、IEEE 754準拠の浮動小数点数となり、内部のビット表現もこれに従っています。

float型の無限大は指数部が255、仮数部が0のビット表現になります。負の無限大は最上位ビットを1にすることで表現します。

floatの最大値・最小値との違い

混同が予想されるものとして、float型で表現可能な最大値と最小値があります。

最大値はfloat.MaxValueプロパティ、最小値はfloat.MinValueプロパティから得られます。

両者は、無限大、負の無限大とは異なり、有効値となっている点で異なります。

float型の計算で最大値・最小値を超えるような計算が行われた場合に、無限大や負の無限大になる場合があります。

// 最大値の取得
var maxValue = float.MaxValue;

// 例えば最大値に2を掛けると無限大になる
var infinity = float.MaxValue * 2;

さいごに

Unity C#で正の無限大、負の無限大を扱う方法を紹介しました。

人によっては、出番はなかなか無いかもしれませんが、効果的に使うと無制限を共通の処理で表すことができて便利な場合があります。

一つの活用方法として参考にしていただければ幸いです。

参考サイト

スポンサーリンク