fc2ブログ
ヽ|∵|ゝ(Fantom) の 開発blog? ホーム »算術関数
このページの記事一覧

【Unity】【C#】double型の Clamp (拡張メソッド)  


 前回 double型の Repeat を作ったので、よく使うものとして、ついでに Clamp も定義しておく。といっても、めちゃくちゃ簡単なので、誰でも作れるものだけどね。

(※) Unity 2020.3.34f1 / Windows11(x64) で確認

●double 型の Clamp 拡張メソッド
using System;

public static partial class MathExtensions //※クラス名は任意
{
/// <summary>
/// double での Clamp.
/// 2024/02/18 Fantom
/// http://fantom1x.blog130.fc2.com/blog-entry-438.html
/// </summary>
/// <param name="value">元の値</param>
/// <param name="min">下限値 (inclusive)</param>
/// <param name="max">上限値 (inclusive)</param>
/// <returns></returns>
public static double Clamp(this double value, double min, double max)
{
if (value < min) return min;
if (max < value) return max;
return value;
}
}

●メインコードでの使用例
using UnityEngine;

Debug.Log(12.0.Clamp(0.0, 5.0)); //5
Debug.Log((-12.0).Clamp(0.0, 5.0)); //0

 Repeat と違い、上限値を"含む"(inclusive) なので注意。上限値を上回ったときや、下限値を下回ったときに、下限~上限値に収める関数だね。よく使うものなので関数として定義した方が楽だと思うが、一行で簡単に書きたいなら、Math クラスの Min, Max を使っても同じことができる。

●Math クラスの Min, Max を使って Clamp と同じことをする
using System;

var value = Math.Max(min, Math.Min(max, value));

 Unity のライブラリみたいに 0~1 に収める Mathf.Clamp01 みたいのを作っても良いね。これはオーバーロードでも良いだろう。Unity には無いが、0~100 なんてのもよく使うので、Clamp0100 みたいのも定義すると便利かもね。

●Clamp01, Clamp0100 を定義する(Clamp のオーバーロード)
using System;

public static partial class MathExtensions //※クラス名は任意
{
/// <summary>
/// double での Clamp01 (0~1).
/// 2024/02/18 Fantom
/// http://fantom1x.blog130.fc2.com/blog-entry-438.html
/// </summary>
/// <param name="value">元の値</param>
/// <returns></returns>
public static double Clamp01(this double value)
{
return Clamp(value, 0, 1);
}

/// <summary>
/// double での Clamp0100 (0~100).
/// 2024/02/18 Fantom
/// http://fantom1x.blog130.fc2.com/blog-entry-438.html
/// </summary>
/// <param name="value">元の値</param>
/// <returns></returns>
public static double Clamp0100(this double value)
{
return Clamp(value, 0, 100);
}
}

 とても地味な関数だけど、double に型変更したとき無いと不便なので、いつでも使えるようにライブラリ化しておくと便利。

(関連記事)
【Unity】【C#】double型の Repeat (拡張メソッド)
【Unity】【C#】範囲を指定できる Mathf.Repeat
【Unity】【C#】倍数での Floor, Ceil, Round(一定間隔での切り捨て、切り上げ、四捨五入) [float 版]
【C#】最大公約数を求める/分数の約分をする(ユークリッドの互除法)
【Java】最大公約数・最小公倍数を求める(ユークリッドの互除法)
【Java】3つ以上の最大公約数を求める(ユークリッドの互除法②)
【Java】拡張ユークリッドの互除法


関連記事
スポンサーサイト



category: Unity

thread: ゲーム開発

janre: コンピュータ

tag: Unityライブラリ  Unityリファレンス  算術関数 
tb: 0   cm: --

【Unity】【C#】double型の Repeat (拡張メソッド)  


 Unity には標準の算術関数:Math クラスを float 型にした Mathf クラスをよく用いるが、double 型だと使えないんだよね。なので、型変更したら関数も Math クラスにしないといけないのだが、全ての関数が一対一で用意されてるわけではない。Mathf.Repeat も Math クラスには無かった…。Repeat って Unity では結構使うこと多いし、ググっても実装例見つからなかったので、double 型でもあったら良いなと思って作った拡張メソッド。

(※) Unity 2020.3.34f1 / Windows11(x64) で確認

●double 型の Repeat 拡張メソッド
using System;

public static partial class MathExtensions //※クラス名は任意
{
/// <summary>
/// double での Repeat.
/// 2024/01/18 Fantom
/// http://fantom1x.blog130.fc2.com/blog-entry-437.html
/// </summary>
/// <param name="value">元の値</param>
/// <param name="length">上限値 (exclusive)[> 0]</param>
/// <returns></returns>
public static double Repeat(this double value, double length)
{
if (length <= 0)
{
throw new AggregateException($"length must be greater than 0 : length = {length}");
}

if (length <= value)
{
return value % length;
}
else if (value < 0)
{
return length - (-value) % length;
}
return value;
}
}

●メインコードでの使用例
using UnityEngine;

Debug.Log(12.0.Repeat(5.0)); //2
Debug.Log((-12.0).Repeat(5.0)); //3
Debug.Log((-12.0).Repeat(-5.0)); //AggregateException

 1つ注意点は、Mathf.Repeat のマニュアルにもあるが、length は 0 より大きい値でないといけない。なので、0 または負の長さはエラーをスローしている。
 これは単純に length が割り算の分母になるからもあるが、0 が分母に使えないのは無論のこと、負の値の剰余は言語によって違ってたりして信用できない値となるので、メソッドに使うのはオススメしない。これは全ての言語に関わることなので、覚えておいた方が良いだろう。以下に資料を載せておく。

(参考)
負数の剰余を計算してはならない

 あと、細かい事だが、例の中で Debug.Log で負の値をカッコで括ってるが("(-12.0).Repeat(5.0)")、付けないと("-12.0.Repeat(5.0)")関数の戻値にマイナスを掛けることになるので注意("-1 * (12.0.Repeat(5.0))"←みたいになる)。場合によっては、負の値にカッコを付けた方が見やすいこともあるね。


(関連記事)
【Unity】【C#】範囲を指定できる Mathf.Repeat
【Unity】【C#】double型の Clamp (拡張メソッド)
【Unity】【C#】倍数での Floor, Ceil, Round(一定間隔での切り捨て、切り上げ、四捨五入) [float 版]
【C#】最大公約数を求める/分数の約分をする(ユークリッドの互除法)
【Java】最大公約数・最小公倍数を求める(ユークリッドの互除法)
【Java】3つ以上の最大公約数を求める(ユークリッドの互除法②)
【Java】拡張ユークリッドの互除法


関連記事

category: Unity

thread: ゲーム開発

janre: コンピュータ

tag: Unityライブラリ  Unityリファレンス  算術関数 
tb: 0   cm: --

【Unity】【C#】音量設定用にデシベル(dB)変換をする  


 これも VRM Live Viewer の音量設定を作ったときのメモ。

 Unity には AudioMixer という複数の音量(Master, Music, SE, ...等)をミキシングして出力できる便利な機能があるのだけれど、設定する値は 0~1f ではなく、デシベル[dB](-80dB~0dB) なんだよね。

 デシベル変換はググればいくらでも出てくるけど、定型処理なら拡張メソッドにしておくと楽なので、いつものように簡単に定義しておいたもの。
あと AudioMixer 使う際に気になる事があったので、少しばかり工夫してる。

(参考)デシベルのすすめ (KAYAC engineers' blog)


(※) Unity 2020.3.34f1 / Windows11(x64) で確認



■音量(0~1f) → デシベル(-80~0dB) に変換する

●音量(0~1f) → デシベル(-80~0dB) に変換する
using UnityEngine;

namespace Exsample
{
public static partial class Extensions //※クラス名は任意
{
//無音とみなすデジベル(dB) や音量
const float DECIBEL_MIN = -80f; //この dB 以下をミュート(音無し)とする
const float DECIBEL_MUTE = DECIBEL_MIN * 10; //単位: dB (-80dB だと僅かに聞こえる気がするので、とりあえず10倍してる)
const float VOLUME_MIN = 0.0001f; //この volume 以下をミュート(音無し)とする

/// <summary>
/// 音量(0~1f) → デシベル(-80(-800)~0dB) に変換
/// ※ただし、volume ≤ 0.0001f のとき -800 [db] を返す
/// (参考) https://techblog.kayac.com/linear-vs-decibel
/// </summary>
/// <param name="volume">0~1f</param>
/// <returns>-80(-800)~0 [dB]</returns>
public static float ToDecibel(this float volume)
{
if (volume <= VOLUME_MIN) //0.0001f を最小値とする
return DECIBEL_MUTE; //-800dB (-80dB だと僅かに聞こえる気がするので、とりあえず10倍してる)

var db = 20 * Mathf.Log10(volume);
return Mathf.Clamp(db, DECIBEL_MUTE, 0f);
}
}
}

 参考資料そのままだが、冒頭に書いた「少しばかり工夫してる」とは、最小値 (0.0001) 以下では DECIBEL_MUTE (-800dB) を返すところで、AudioMixer の Threshold のデフォ値(-80dB) 付近だと、わずかに音が聞こえる気がするからだ。もちろん Threshold の値を上げても良いが、毎回調整するのは面倒なので(笑)、とりま 10倍した値(-800dB)を返すようにしてる。これをそのまま AudioMixer.SetFloat に当ててやれば、確実に無音(ミュート)できる。

(参考)デシベルのすすめ (KAYAC engineers' blog)

 アプリではわかりやすいように音量を 0~100(%) 表記してるが、やはり定型処理となるので、以下のような簡単な拡張メソッド(.NET 4.x)を作るのも良いだろう。

//音量(0~100%) → デシベル(-80(-800)~0dB) に変換
public static float PercentToDecibel(this float per) => ToDecibel(per * 0.01f);




■デシベル(-80~0dB) → 音量(0~1f) に変換する

●デシベル(-80~0dB) → 音量(0~1f) に変換する
using UnityEngine;

namespace Exsample
{
public static partial class Extensions //※クラス名は任意
{
/// <summary>
/// デシベル(-80~0dB) → 音量(0~1f) に変換
/// (参考) https://techblog.kayac.com/linear-vs-decibel
/// </summary>
/// <param name="decibel">-80~0dB</param>
/// <returns>0~1f</returns>
public static float FromDecibel(this float decibel)
{
if (decibel <= DECIBEL_MIN) //-80dB を最小値とする
return 0f;

return Mathf.Pow(10f, decibel / 20f);
}
}
}

 これも参考資料そのままなので、詳細はそちらを参考にして欲しい。

(参考)デシベルのすすめ (KAYAC engineers' blog)

 これも少し手を加えたのは、-80dB を引数に与えると 0.0001 の計算値になるので、強制的に 0 (無音) にしている所。この方が実用的で使いやすかっただけのこと。

 例えば簡単にテストすると、以下のような結果になる。

var volMin = 0f;
var volMax = 1f;
var volOverMin = -1f;
var volOverMax = 2f;

//volume (0~1f) → dB (-80(-800)~0dB) 変換
var dBMin = volMin.ToDecibel();
var dBMax = volMax.ToDecibel();
var dBOverMin = volOverMin.ToDecibel();
var dBOverMax = volOverMax.ToDecibel();

Debug.Log($"volMin = {volMin}, ToDecibel = {dBMin}");
Debug.Log($"volMax = {volMax}, ToDecibel = {dBMax}");
Debug.Log($"volOverMin = {volOverMin}, ToDecibel = {dBOverMin}");
Debug.Log($"volOverMax = {volOverMax}, ToDecibel = {dBOverMax}");

//dB (-80(-800)~0dB) → volume (0~1f) 変換
var dBMinToVol = dBMin.FromDecibel();
var dBMaxToVol = dBMax.FromDecibel();
var dBOverMinToVol = dBOverMin.FromDecibel();
var dBOverMaxToVol = dBOverMax.FromDecibel();

Debug.Log($"dBMin FromDecibel = {dBMinToVol}");
Debug.Log($"dBMax FromDecibel = {dBMaxToVol}");
Debug.Log($"dBOverMin FromDecibel = {dBOverMinToVol}");
Debug.Log($"dBOverMax FromDecibel = {dBOverMaxToVol}");

volMin = 0, ToDecibel = -800
volMax = 1, ToDecibel = 0
volOverMin = -1, ToDecibel = -800
volOverMax = 2, ToDecibel = 0
dBMin FromDecibel = 0
dBMax FromDecibel = 1
dBOverMin FromDecibel = 0
dBOverMax FromDecibel = 1








(関連記事)
【Unity】【C#】HDR Color を計算(変換)する
【Unity】【C#】ガンマ(Gamma, sRGB) - リニア(Linear) 値の相互変換
【C#】文字列 → float (浮動小数点) 変換でエラーが出るときは…


関連記事

category: Unity

thread: ゲーム開発

janre: コンピュータ

tag: Unityライブラリ  Unityリファレンス  算術関数  サウンド 
tb: 0   cm: --

【Unity】【C#】ガンマ(Gamma, sRGB) - リニア(Linear) 値の相互変換  


 そろそろ UniVRM をアップデートしたいなぁ、と思ったけど、とうとう UniVRM0.79 以降はカラースペース(Color Space)をリニア(Linear)に統一するらしく、インポートしたら強制的に変更されるようになってしまった。

 VRM Live Viewer は3年前、Unity2017初期の頃からはじまったのだが、CRS ステージは Unity4, Crystal ステージは Unity5 時代のものを流用してるんだよね。なので、ガンマ(Gamma)スペースなのだ。

 まぁ、正直言って、特に Unity2018 以降の機能は Linear 依りになってきたので(なぜか今でも Unity のデフォは Gamma だが)、いずれ移行したいとは思ってたんだけどね。

 しかし、さすがにマイナーバージョンアップデートで、前後の互換性がないのはおかしいし(不具合にしか見えないため)、メジャーアプデとして考えていた。なので急遽移行を迫られる形になってしまった。でも Color Space 変更って、プロジェクト素材全てに影響するので、とてもじゃないけどすぐにはできないんだよね(見た目がかなり変わる)。

 なので、自動化できるところはスクリプトで変換などするために、色々調べることになった。これはそのメモ。ほぼ出典そのままだが、汎用的に使えるので掲載しておこう。


(※) Unity 2019.4 / Windows10(x64) で確認



■Unity の Color, Mathf での変換

 ちなみに、Unity では Color 構造体が linear, gamma というプロパティがあり、Mathf には Mathf.GammaToLinearSpace, Mathf.LinearToGammaSpace という関数があるので、簡単に変換できる。例えば以下のようにできる。

using UnityEngine;

//ガンマ→リニア
var gammaColor = new Color(0.3f, 0.4f, 0.5f);
var linearColor = gammaColor.linear; //→ RGBA(0.073, 0.133, 0.214, 1.000)

var linearValue = Mathf.GammaToLinearSpace(0.5f); //→ 0.2140411ff

//リニア→ガンマ
var linearColor = new Color(0.073f, 0.133f, 0.214f);
var gammaColor = linearColor.gamma; //→ RGBA(0.300, 0.400, 0.500, 1.000)

var gammaValue = Mathf.LinearToGammaSpace(0.2140411f); //→ 0.5f

 これで事足りてしまう場合は良いのだが、もう少しつっこんだ実装をしたいとか、高速化した近似式を使いたいというときもあるだろう。それらは以降のようになる。



■汎用的な値(0~1f:正規化した値)での変換

●定義からの厳密な Gamma - Linear 相互変換 (0~1f:正規化した値での計算)
using UnityEngine;

/// <summary>
/// ガンマ(sRGB)→リニア (0.0-1.0:正規化した値) 色空間変換 (厳密なコード)
/// (参考)
/// https://en.wikipedia.org/wiki/SRGB
/// https://tech.cygames.co.jp/archives/2339/
/// </summary>
/// <param name="gamma">0.0-1.0</param>
/// <returns>0.0-1.0</returns>
public static float ToLinearValueStrict(this float gamma)
{
if (gamma <= 0.04045f)
{
return gamma / 12.92f;
}
else
{
return Mathf.Pow((gamma + 0.055f) / 1.055f, 2.4f);
}
}

/// <summary>
/// リニア→ガンマ(sRGB) (0.0-1.0:正規化した値) 色空間変換 (厳密なコード)
/// (参考)
/// https://en.wikipedia.org/wiki/SRGB
/// https://tech.cygames.co.jp/archives/2339/
/// </summary>
/// <param name="linear">0.0-1.0</param>
/// <returns>0.0-1.0</returns>
public static float ToGammaValueStrict(this float linear)
{
if (linear <= 0.0031308f)
{
return linear * 12.92f;
}
else
{
return 1.055f * Mathf.Pow(linear, 0.4166666f) - 0.055f; //0.4166666f = 1/2.4
}
}

 ここでは sRGB とガンマを同等に扱っているが、実際にはガンマ補正はディスプレイや機器などで値が違うようなので、あくまで一般的な仕様に合わせたものだと思って欲しい。

 式は以下の参考資料そのままだ。定義は Wikipedia に掲載されている。

(定義) sRGB (From sRGB to CIE XYZ, From CIE XYZ to sRGB)
(参考:式) 物理ベースレンダリング -リニアワークフロー編



●高速化近似式 (2.2乗, 1/2.2乗) での変換

 また、式の参考ページにも記載されているが、高速化用の近似式は以下のようになる。

●高速化近似式 Gamma - Linear 相互変換 (0~1f:正規化した値での計算)
using UnityEngine;

/// <summary>
/// ガンマ(sRGB)→リニア (0.0-1.0:正規化した値) 色空間変換 (高速化近似式: 2.2乗)
/// (参考) https://tech.cygames.co.jp/archives/2339/
/// </summary>
/// <param name="gamma">0.0-1.0</param>
/// <returns>0.0-1.0</returns>
public static float ToLinearValueFast(this float gamma)
{
return Mathf.Pow(gamma, 2.2f); //or 2.233333f
}

/// <summary>
/// リニア→ガンマ(sRGB) (0.0-1.0:正規化した値) 色空間変換 (高速化近似式: 1/2.2乗)
/// (参考) https://tech.cygames.co.jp/archives/2339/
/// </summary>
/// <param name="linear">0.0-1.0</param>
/// <returns>0.0-1.0</returns>
public static float ToGammaValueFast(this float linear)
{
return Mathf.Pow(linear, 0.45454545f); //1/2.2
}

 なぜそうなるのかというのは、以下を参照すると良いだろう。とてもわかりやすく解説されている。

(参考資料)
ガンマ補正のうんちく
分かる!リニアワークフローのコンポジット

 まぁ端的に言うと、曲線が似てれば、値も似るということだね(笑)。英語では「Magic Number」みたいにも言われている。

 ちなみに、冒頭に書いた Unity の Color.linear や Color.gamma, Mathf.GammaToLinearSpace, Mathf.LinearToGammaSpace と値を照合してみたら、「~Strict」の関数(厳密なコード)はほぼ同じで、「~Fast」(高速化近似式)の方は6割くらい一致するようだ(※ただし、誤差を甘めで、小数点3ケタくらいで比較した場合。べき乗を 2.233333f にすると 67%くらい)。しかし見た目では、静止画ならともかく、動いてる絵なら見分けが付かないくらいだ。

 また、これらの式をシェーダに使っている例もある。というより、近いものを Unity の PostProcessing で実装されているらしい。最後に抜粋してるので、興味があったら見てみると良い。



●シンプルな3次の高速近似式での変換

 また、下記のシェーダの計算を見ていると、2.2乗の近似式は単純に2乗(c * c)にされているが、もう1つ近似式があるね。コメントの ref の先に解説もあるが、なるほど計算負荷が低いらしい(基本的に平方根やべき乗などは、単純な掛け算や足し算より負荷が高いため)。

 もう1つの高速化近似式を C# で書いてみよう(そのまま)。

●シンプルな3次の高速近似式での Gamma → Linear 変換 (0~1f:正規化した値での計算)
using UnityEngine;

/// <summary>
/// ガンマ(sRGB)→リニア (0.0-1.0:正規化した値) 色空間変換 (高速化近似式: シンプルな3次)
/// (参考) http://chilliant.blogspot.com.au/2012/08/srgb-approximations-for-hlsl.html?m=1
/// </summary>
/// <param name="gamma">0.0-1.0</param>
/// <returns>0.0-1.0</returns>
public static float ToLinearValueFastCubic(this float gamma)
{
return gamma * (gamma * (gamma * 0.305306011f + 0.682171111f) + 0.012522878f);
}

 最初の高速近似式(2.2乗)のコード内のコメントに「or 2.233333f」と書いてあるのは、こちらの資料にあったからだ。

 実際に試してみると、こちらも動いてる分には、ぱっと見た目わからない。平方根使うより計算負荷が軽いので、Unity も採用しているのだろう。これは助かる。

(参考資料) sRGB Approximations for HLSL



■シェーダでの利用

 以下のコードは実際に Unity の PostProcessing で使われているようだ。そのまま抜粋させて頂いた。

●シェーダ内 (.shader 等)での Gamma - Linear 相互変換 (0~1f:正規化した値での計算)
// sRGB transfer functions
// Fast path ref: http://chilliant.blogspot.com.au/2012/08/srgb-approximations-for-hlsl.html?m=1
//
half SRGBToLinear(half c)
{
#if USE_VERY_FAST_SRGB
return c * c;
#elif USE_FAST_SRGB
return c * (c * (c * 0.305306011 + 0.682171111) + 0.012522878);
#else
half linearRGBLo = c / 12.92;
half linearRGBHi = PositivePow((c + 0.055) / 1.055, 2.4);
half linearRGB = (c <= 0.04045) ? linearRGBLo : linearRGBHi;
return linearRGB;
#endif
}

half3 SRGBToLinear(half3 c)
{
#if USE_VERY_FAST_SRGB
return c * c;
#elif USE_FAST_SRGB
return c * (c * (c * 0.305306011 + 0.682171111) + 0.012522878);
#else
half3 linearRGBLo = c / 12.92;
half3 linearRGBHi = PositivePow((c + 0.055) / 1.055, half3(2.4, 2.4, 2.4));
half3 linearRGB = (c <= 0.04045) ? linearRGBLo : linearRGBHi;
return linearRGB;
#endif
}

half4 SRGBToLinear(half4 c)
{
return half4(SRGBToLinear(c.rgb), c.a);
}

half LinearToSRGB(half c)
{
#if USE_VERY_FAST_SRGB
return sqrt(c);
#elif USE_FAST_SRGB
return max(1.055 * PositivePow(c, 0.416666667) - 0.055, 0.0);
#else
half sRGBLo = c * 12.92;
half sRGBHi = (PositivePow(c, 1.0 / 2.4) * 1.055) - 0.055;
half sRGB = (c <= 0.0031308) ? sRGBLo : sRGBHi;
return sRGB;
#endif
}

half3 LinearToSRGB(half3 c)
{
#if USE_VERY_FAST_SRGB
return sqrt(c);
#elif USE_FAST_SRGB
return max(1.055 * PositivePow(c, 0.416666667) - 0.055, 0.0);
#else
half3 sRGBLo = c * 12.92;
half3 sRGBHi = (PositivePow(c, half3(1.0 / 2.4, 1.0 / 2.4, 1.0 / 2.4)) * 1.055) - 0.055;
half3 sRGB = (c <= 0.0031308) ? sRGBLo : sRGBHi;
return sRGB;
#endif
}

half4 LinearToSRGB(half4 c)
{
return half4(LinearToSRGB(c.rgb), c.a);
}

 内容的には、厳密なコード高速化近似式 (2.2乗 や 1/2.2乗) に同じか近いね。プリプロセッサの「USE_VERY_FAST_SRGB」や「USE_FAST_SRGB」で実行速度を選択できるらしい。

 PositivePow は以下の参考資料を(LIGHT11)見て欲しい。正の値しか使わないのなら、ただの pow() でも可能のようだ。

(参考)
PostProcessing/PostProcessing/Shaders/Colors.hlsl (Unity の PostProcessing 内)
【Unity】シェーダにおける値のリニア <-> sRGB変換関数 (LIGHT11:PositivePow 掲載)

●PositivePow (負の値にしないべき乗) 抜粋
#define FLT_EPSILON     1.192092896e-07

// Using pow often result to a warning like this
// "pow(f, e) will not work for negative f, use abs(f) or conditionally handle negative values if you expect them"
// PositivePow remove this warning when you know the value is positive and avoid inf/NAN.
float PositivePow(float base, float power)
{
return pow(max(abs(base), float(FLT_EPSILON)), power);
}

float2 PositivePow(float2 base, float2 power)
{
return pow(max(abs(base), float2(FLT_EPSILON, FLT_EPSILON)), power);
}

float3 PositivePow(float3 base, float3 power)
{
return pow(max(abs(base), float3(FLT_EPSILON, FLT_EPSILON, FLT_EPSILON)), power);
}

float4 PositivePow(float4 base, float4 power)
{
return pow(max(abs(base), float4(FLT_EPSILON, FLT_EPSILON, FLT_EPSILON, FLT_EPSILON)), power);
}




 結局、どれを使うかはケースバイケースだと思うが、実装を知ってると色々応用が効くので知っておいて損は無い。例えば、ガンマ補正の値は 2.2乗 みたいになってるが(sRGBディスプレイの現在のデファクトスタンダードであり、過去には色々値が異なっていたらしい)、これを引数をして変更すると、見た目も変わる。これを応用してシェーダの方で Properties に入れておくと、インスペクタで変化の加減を調整できるので、とても便利だ。

 実際、VRM Live Viewer のプロジェクト内の素材を Linear 用に調整している最中だが、透過の無いテクスチャなどは、マテリアルの調整やいっそ PhotoShop でテクスチャの色調補正すれば、Gamma のときと同じ感じになるので事足りる。しかし、透過や反射するようなマテリアル(色や光の合成が行われるマテリアル)などは、どんなに調整しても Gamma のときと同じようにはならない(参考資料の「加算/合成が変わる」がわかりやすい)。そういう場合は、シェーダに変換式を入れないと、それっぽくはならないようだ(それでも完全には無理だが)。

(参考資料)
分かる!リニアワークフローのコンポジット






(関連記事)
【Unity】Standard Assets の Flare は Gamma 用だった?
【Unity】色形式:Unity の Color と Android の ARGB(int32) の相互変換をする
【Unity】【C#】Quality (グラフィック品質) を文字列で取得/設定する
【Unity】【C#】画面解像度とアクペクト比(整数)を求める
【HTML】HTMLカラー名・カラーコード表


関連記事

category: Unity

thread: ゲーム開発

janre: コンピュータ

tag: Unityリファレンス  C#ライブラリ  グラフィックス  算術関数  シェーダ 
tb: 0   cm: --

【C#】文字列 → float (浮動小数点) 変換でエラーが出るときは…  


 もう随分前の話になるが、フランス語圏の人から「VRM Live Viewer を使いたいのだが、起動ができない」というメッセージが来た。

 とりあえずアプリのバージョンと状況を聞いて確認してみたが、普通に起動できる。念の為、BOOTH にも出しているので DL して試したが、やはり同じ結果だ。

 しばらく何の事か全く見当が付かなかったのだが、根気よくスクショを送って貰ったり、動画を見せて貰ったりしているうちに、環境の違い(OS)くらいしかもう無いと意見が一致したので、彼は英語を、私はフランス語をインストールして OS を再起動してみた。

 そしたらどうだ。彼は「起動に成功した」と言い、私は彼が言っていたように起動に失敗した。

 原因は起動時に読み込まれる BVH ファイルで、そのファイルはテキストで書かれていて、小数点は "."(ドット) で書かれている。実はフランス語、アイスランド語など特定の言語圏では、小数点は "," (カンマ) で書くので、気の利いた OS (笑)がエラーを吐いていたのだ。

 かくして、ライブラリ作者に不具合報告をして、今ではそのフランスの VTuber もめでたく利用して貰っている。

特定の言語環境下において、BVHロードに失敗する

 まぁ、そんなこんなで「文字列を float (浮動小数点)に変換するなら、拡張メソッドを作っておいた方が良いよ」(※使うなら double 等も) という事で、簡単なものを紹介しておこう。



●フランス語、アイスランド語など特定の言語圏でも対応できる 文字列 → float (浮動小数点) 変換
using System;
using System.Globalization;

public static class Extensions //名前は任意
{
/// <summary>
/// 文字列 → float 変換 (CultureInfo.InvariantCulture 指定)
/// </summary>
/// <param name="s">変換元文字列</param>
/// <returns>変換後の float (失敗は 0)</returns>
public static float ToFloat(this string s)
{
if (float.TryParse(s, NumberStyles.Number, CultureInfo.InvariantCulture, out var value))
{
return value;
}
return 0f;
}


/// <summary>
/// 文字列 → float 変換 (CultureInfo.InvariantCulture 指定)
/// </summary>
/// <param name="s">変換元文字列</param>
/// <param name="result">変換成功時 = float 値 / 変換失敗時 = 0</param>
/// <returns>true = 変換成功 / false = 変換失敗</returns>
public static bool TryParseFloat(this string s, out float result)
{
if (float.TryParse(s, NumberStyles.Number, CultureInfo.InvariantCulture, out var value))
{
result = value;
return true;
}
result = 0;
return false;
}
}

●メインコード例
using System;

var s = "1.234";
Console.WriteLine("ToFloat : " + s.ToFloat());

if (s.TryParseFloat(out var result))
{
Console.WriteLine("TryParseFloat : " + result);
}
else
{
Console.WriteLine("TryParseFloat failed");
}

ToFloat : 1.234
TryParseFloat : 1.234

 結果だけ見ると何て事ないのだが、この関数なら、フランス語、アイスランド語など特定の言語圏でもエラーにはならない。

 ちなみに、float 変換のオプションに使っている「CultureInfo.InvariantCulture」は「カルチャに依存しない」(無視する) ものらしい。要するに OS の言語とは関係なく、常に一定(英語圏)で変換されるようだ。むしろそっちの方がデフォだと有り難いのだが…(例えば文字列比較の Equals 等もデフォだとカルチャが効くので言語によって結果が異なる可能性がある)。

 必要なら double 等、他の浮動小数点も作っておいた方が良いだろう。

 動作確認するには OS にフランス語を入れて、OS の言語設定でフランス語に設定した後で、OS を再起動して確かめるしかないが、特に最近はアプリが世界中で使われるような時代になったので、これは常備した方が良いだろう。実際私もフランスの人から報告貰うまでは考えもしなかった。



 実は、不具合報告って開発者にとっては非常に有用な情報なので「なんか動作がおかしいな…」と思ったら、連絡してあげると良い。我々はバグ取りのエキスパートでもあるので、すぐに原因究明から修正案まで出せると思う。

 実際、この不具合(特定の言語環境下において、BVHロードに失敗する) はライブライリ元の UniVRM が抱えていた問題だったので、これが Fix されると、フランス圏の人もアプリや VRM が利用できるようになったわけだしね(少なくとも BVH を使うアプリはそれまでフランス圏では利用できなかったハズ:3tene とかも BVH 機能入ってた気がする)。

 単純に不具合が直ると自分も幸せだし、他の多くの利用者も幸せになれるしね(笑)。





(関連記事)
【Unity】【C#】StartsWith, EndsWith が遅いのなら、Equals も遅いのか?
【Unity】【C#】範囲を指定できる Mathf.Repeat
【C#】【Unity】enum 型と string, int 型の相互変換など
【Unity】色形式:Unity の Color と Android の ARGB(int32) の相互変換をする


関連記事

category: C#

thread: プログラミング

janre: コンピュータ

tag: C#ライブラリ  C#リファレンス  算術関数 
tb: 0   cm: --


プロフィール

Social

検索フォーム

全記事一覧

カテゴリ

ユーザータグ

最新記事

リンク

PR

▲ Pagetop