Unity Matrix4x4で連立方程式を解く
// 四点を通る三次関数を得る static public void CalculateCubicFunctionBy4Points( float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) { var matrix = new Matrix4x4(); matrix[0, 0] = x1 * x1 * x1; matrix[0, 1] = x1 * x1; matrix[0, 2] = x1; matrix[0, 3] = 1f; matrix[1, 0] = x2 * x2 * x2; matrix[1, 1] = x2 * x2; matrix[1, 2] = x2; matrix[1, 3] = 1f; matrix[2, 0] = x3 * x3 * x3; matrix[2, 1] = x3 * x3; matrix[2, 2] = x3; matrix[2, 3] = 1f; matrix[3, 0] = x4 * x4 * x4; matrix[3, 1] = x4 * x4; matrix[3, 2] = x4; matrix[3, 3] = 1f; var inversedMatrix = matrix.inverse; var rightMatrix = new Vector4(y1, y2, y3, y4); var a = Vector4.Dot(inversedMatrix.GetRow(0), rightMatrix); var b = Vector4.Dot(inversedMatrix.GetRow(1), rightMatrix); var c = Vector4.Dot(inversedMatrix.GetRow(2), rightMatrix); var d = Vector4.Dot(inversedMatrix.GetRow(3), rightMatrix); // a * x^3 + b * x^2 + c * x + d }
徐々に消えるライト
やること
爆発エフェクトなんかを作るとき、オブジェクトにライトを持たせる場合がある。 このとき、普通にエフェクトオブジェクトにライトコンポーネントを持たせただけだと、オブジェクトがDestroyされた瞬間にライトもパッと消えてしまう。余韻をもってじわりと消えてほしい。
(光源が消えたらその瞬間に暗くなるのがリアルではあるんだけど、忘れよう。)
コード
Unity5.3.4f1
using UnityEngine; using System.Collections; using System.Linq; namespace TSKT { [RequireComponent(typeof(Light))] public class EasingLight : MonoBehaviour { static bool applicationQuitting = false; Light light; Light Light { get { return light ?? (light = GetComponent<Light>()); } } [SerializeField] [Range(0.01f, 1f)] float turnOnDuration = 0.1f; [SerializeField] [Range(0.01f, 1f)] float turnOffDuration = 1f; IEnumerator TurnOnCoroutine() { var initialIntensity = Light.intensity; var v = new EasingValue(); v.JumpTo(0f); v.EaseTo(initialIntensity, 0.1f); Light.intensity = 0f; while (true) { yield return null; Light.intensity = v.Value; if (v.Completed) { break; } }; } void OnApplicationQuit() { // OnDisableはエディタでの再生終了時にも処理が走って嫌な事になるので、終了を検知する。 applicationQuitting = true; } void OnEnable() { StartCoroutine(TurnOnCoroutine()); } void OnDisable() { if (applicationQuitting) { return; } var obj = new GameObject(); obj.transform.position = transform.position; obj.transform.rotation = transform.rotation; obj.transform.localScale = transform.lossyScale; Destroy(obj, turnOffDuration); var cloneLight = obj.AddComponent<Light>(); // プロパティのコピーが綺麗に書けなかったので、ライトのtypeによっては上手くいかないかもしれないし、将来的にプロパティが増えたりしたら目も当てられない。 cloneLight.type = Light.type; cloneLight.bounceIntensity = Light.bounceIntensity; cloneLight.color = Light.color; cloneLight.flare = Light.flare; cloneLight.cullingMask = Light.cullingMask; cloneLight.cookie = Light.cookie; cloneLight.cookieSize = Light.cookieSize; cloneLight.range = Light.range; cloneLight.intensity = Light.intensity; cloneLight.shadows = Light.shadows; var v = new EasingValue(); v.JumpTo(light.intensity); v.EaseTo(0f, turnOffDuration); TaskManager.Instance.Repeat(() => { if (!cloneLight) { return false; } cloneLight.intensity = v.Value; return !v.Completed; }); } } }
EasingValueとかTaskManagerは自作クラスなのでなんじゃこりゃって感じだが、値を徐々に動かすためのしくみと思いねえ。コルーチンとMathf.Lerpあたりで書き換えられる。こだわり抜くならAnimationCurveも。
やってることは強引なもので、オブジェクトがDestoryされる瞬間にライトの複製を作ってそっちをじわじわ消すというだけ。
ついでにライトの点き始めもじわじわ光るようにしておいた。
【Unity】MultiModeなSpriteの参照を取得し直す
問題
MultiModeなSpriteの参照をGameObject
だかScriptableObject
が持っているとき。
画像の変更か何かがあってSliceし直すと、Spriteへの参照がMissingになる。これをなんとかする。
理屈
Spriteが生成し直されるのはどうしようもない(多分)ので、Textureと位置からSpriteを再取得する。
雑コード
だいたいこんなん。
Unity5.3.2p3
public class Hoge : MonoBehaviour { #if UNITY_EDITOR [SerializeField] Texture texture; [SerializeField] Rect spriteRect; #endif [SerializeField] Sprite sprite; #if UNITY_EDITOR void OnValidate() { if (!texture) { return; } if (sprite) { return; } var path = AssetDatabase.GetAssetPath(texture); var sprites = AssetDatabase.LoadAllAssetRepresentationsAtPath(path); foreach (Sprite sprite in sprites) { if (spriteRect == sprite.rect) { this.sprite = sprite; EditorUtility.SetDirty(this); break; } } } #endif }
用途
マップチップなんかに使えるはず。
- マップチップ画像はMutliSpriteで作成する。
- マップチップ画像はあとでチップが追加されたりするので、開発中にSliceをやり直す機会が発生する。
進捗っぽいの
イェイ pic.twitter.com/WMQ6RCOtx6
— enu (@_enu) 2016, 2月 8
フトチャン pic.twitter.com/8w1lgW8ftD
— enu (@_enu) 2016, 2月 10
息抜きにマントシェーダ。ただしこのままでは副作用があるので、使えるものにするにはあと二手間ぐらい要る。メンドいぜよ。 pic.twitter.com/9KjBTEROJA
— enu (@_enu) 2016, 2月 11
【Unity】範囲指定可能なブラーエフェクト
そもそも、2Dベースなら真面目に被写界深度エフェクトをやることもないよね!
というわけで、範囲指定ができるブラーエフェクトを作った。
理屈
ImageEffectのDepthOfFieldエフェクトは深度バッファを参照してブラー範囲を決めることでピンボケを表現している。
この深度バッファ参照部分を改造し、テクスチャアセット参照にすることによって、範囲限定ブラーになると。
メモ
テクスチャはモノクロで良いので8bit形式推奨。白い箇所にブラーがかかり、黒い箇所はそのまま描画される。
親クラスとシェーダはImageEffectのものを参照しているので、そのへんインポートしておかなければならない。
コード
Unityバージョンは5.3.2p1
ブツ
ボカす部分固定のナンチャッテ被写界深度 pic.twitter.com/5j63fjIK64
— enu (@_enu) 2016年1月30日
【Unity】Orthographicカメラで被写界深度エフェクトを使う
Sprite+Orthographicカメラという極北で被写界深度エフェクトテスト pic.twitter.com/4VAVI4N5sj
— enu (@_enu) 2016, 1月 30
やること
ImageEffectに含まれるDepthOfFieldエフェクト。
これはperspectiveカメラで使うことを前提にしており、orthographicカメラで使おうとするとうまくいかない。なんとかする。
Unityバージョン
5.3.2p1
手順
DepthOfFieldScatter.shaderを開けて
d = Linear01Depth (d);
となっている箇所をコメントアウトすれば良い。
どうしてこうなるのか?
orthographicカメラとperspectiveカメラではdepthの算出方法が異なるため。
詳しくは「深度バッファ 精度」あたりでググるとそれっぽいのが出る。
進捗
ドット絵作業進めた。
今週もドット絵すすめる。