今すぐ使える?!クリスマスイブっぽいイージング関数を作ってみよう!

Tech KAYAC Advent Calendar 2020 24日目の記事です。


こんにちは!

カヤック意匠部アートディレクターの おばら です。

今日はクリスマスイブということで

イブっぽい「イージング関数」を作ってみようと思います。

f:id:tsmallfield:20201224013617g:plain
EaseInSineChristmasTree

まずはイージングについて軽くおさらい。

「In」「Out」「InOut」?

f:id:tsmallfield:20201223144728p:plain

「In」「Out」「InOut」(「OutIn」)はイージングカーブの曲がり具合。

  • 徐々に傾きが大きくなっていくなら「In」

  • 徐々に傾きが小さくなっていくなら「Out」

ふむふむ。

位置の時間経過のアニメーションに使うとしたら

  • だんだん早くなるなら「In」

  • だんだん遅くなるなら「Out」

と。

「Sine」「Cubic」「Circ」、、?

イージング関数がどんな計算式で作られているかが名前で分かる場合もあります。

-「Sine」なら y = sin(x)

-「Cubic(Power3)」なら3次関数 y = x3

-「Circ」なら円、 x2 + y2 = 1

という具合。

いろんな作り方があるんですね。

(環境によってはベジェ曲線で指定する方法も)

EaseInSine を作ってみる

まずは練習。

EaseInSine を作ってみましょう。

「Sine」、つまり y = sin(x) を考えます。

y = sin(x)

y = sin(x)

グラフまで表示してくれるなんて、Google検索便利すぎです。

「In」になっている部分を探すと。。

f:id:tsmallfield:20201223133038p:plain

あった!

これを

x = 0 のときに y = 0

x = 1 のときに y = 1

となるよう調整していきます。

縦軸Yをあわせる

上(+方向)に 1 ずらします。

y = sin(x) + 1

f:id:tsmallfield:20201221234647p:plain

y が 0〜1の範囲になりました。

横軸Xをあわせる

横方向にギュッと縮め、

右(+方向)に π/2、つまり 90° ずらします。

y = sin(x * π/2 - π/2) + 1

f:id:tsmallfield:20201223133514p:plain

できた!

JavaScript で書くと、

function easeInSine(x) {
    return Math.sin(x * Math.PI / 2 - Math.PI / 2) + 1;
}

ちょっとだけリファクタリング

実は sin(x - π/2) は -cos(x) と同じ。

つまり

y = sin(x * π/2 - π/2)

y = -cos(x * π/2) + 1

と書き直せちゃいます。

つまり、

function easeInSine(x) {
    return -Math.cos(x * Math.PI / 2) + 1;
}

- Math.PI / 2 がなくなった分シンプルになりました。

答え合わせ

よく使われていそうなライブラリの実装と比較してみます。

jQuery.easing の EaseInSine

https://github.com/gdsmith/jquery.easing/blob/master/jquery.easing.js#L102-L104

easeInSine: function (x) {
    return 1 - cos( x * PI/2 );
},

同じ!

GSAP の EaseInSine

https://github.com/greensock/GSAP/blob/147a6b6594d6bf272ab74ddbbbb2060190c6cce5/src/gsap-core.js#L1046

_insertEase("Sine", p => p === 1 ? 1 : -_cos(p * _HALF_PI) + 1);

同じ! (GSAPは In をベースにそれを反転したりくっつけたりして Out, InOut を生成しています)

https://github.com/greensock/GSAP/blob/147a6b6594d6bf272ab74ddbbbb2060190c6cce5/src/gsap-core.js#L988

_insertEase = (names, easeIn, easeOut = p => 1 - easeIn(1 - p), easeInOut = (p => p < .5 ? easeIn(p * 2) / 2 : 1 - easeIn((1 - p) * 2) / 2)) => {

easeOut = p => 1 - easeIn(1 - p)
easeInOut = (p => p < .5 ? easeIn(p * 2) / 2 : 1 - easeIn((1 - p) * 2) / 2)

の部分で(easeOut, easeInOut が明示的に指定されない場合は)ゴニョゴニョしてますね!

EaseOutSine, EaseInOutSine も作ってみる

EaseOutSine

y = sin(π * x / 2)

f:id:tsmallfield:20201222002913p:plain

function easeOutSine(x) {
    return Math.sin(Math.PI * x / 2);
}

EaseInOutSine

y = (sin(πx - π / 2) + 1) / 2

f:id:tsmallfield:20201223133843p:plain

function easeInOutSine(x) {
    return (Math.sin(Math.PI * x - Math.PI / 2) + 1) / 2;
}

Math.cos() で書き直すと

function easeInOutSine(x) {
    return (1 - Math.cos(Math.PI * x)) / 2;
}

N次関数系も作ってみる

1次関数でつくるイージング(Linear, None)

まずは基本の1次関数(Linear function)

y = x

f:id:tsmallfield:20201223134118p:plain

function linear(x) {
    return x;
}

2次関数でつくるイージング(Quad, Power2)

2次関数(Quadratic Function)

つまり

xの2乗(x to the power of 2)

y = x2

f:id:tsmallfield:20201222004012p:plain

function easeInQuad(x) {
    return x**2;
}

もしくは

function easeInQuad(x) {
    return x*x;
}

もしくは

function easeInQuad(x) {
    return Math.pow(x, 2);
}

など。

Math.pow()powpowerpow だったんですね。)

3次関数でつくるイージング(Cubic, Power3)

3次関数(Cubic Function)

xの3乗(x to the power of 3)

y = x3

f:id:tsmallfield:20201223134357p:plain

function easeInCubic(x) {
    return x**3;
}

もしくは

function easeInCubic(x) {
    return x*x*x;
}

もしくは

function easeInCubic(x) {
    return Math.pow(x, 3);
}

など。

どんどんカーブが急になっていきますね。

0.25乗とか、0.5乗 とかも面白そうです。

円(Circ)

円の式は

1 = x2 + y2

変形して1上にずらすと

y = -sqrt(1 - x2)+1

f:id:tsmallfield:20201223134641p:plain

function easeInCirc(x) {
    return -Math.sqrt(1 - x**2)+1;
}

グラフにしてみる

EaseInSine を Canvas 2D でグラフにしてみました。

1) 自作版

See the Pen Drawing Easing Curve: EaseInSine by Tohl SMALLFIELD (@tsmallfield) on CodePen.

2) jQuery.easing.easeInSine

See the Pen Drawing Easing Curve: jQueryEasing EaseInSine by Tohl SMALLFIELD (@tsmallfield) on CodePen.

3) GSAP Sine.easeIn

See the Pen Drawing Easing Curve: GSAP EaseInSine by Tohl SMALLFIELD (@tsmallfield) on CodePen.

同じですね。

アニメーションしてみる

自作したEaseInSine関数でなにか動かしてみましょう。

ミニマムなサンプルコードを用意しました。

See the Pen Preview Easing: EaseInSine by Tohl SMALLFIELD (@tsmallfield) on CodePen.

いい感じですね。

「In」ではなく「Out」にするともっと気持ちよくなりそうです。

イブっぽいイージング関数を作ってみる

さて、お待たせしました。

ようやく本題です。

イージング関数の作り方がわかったので

ちょっと遊んでみます。

EaseInSineChristmasTree

EaseInSine (と Circ)で作ったクリスマスツリーです。

諸事情により倒れたクリスマスツリーとなっております。

See the Pen Drawing Easing Curve: EaseInSineChristmasTree by Tohl SMALLFIELD (@tsmallfield) on CodePen.

3歩進んで2歩下がる的な。

そもそも目標値に到達してくれません。

とんでもないイージング関数です。

使い所はあるんでしょうか。

とりあえずアニメーションに使ってみましょう。

1) アニメーション機能含めフルスクラッチ版

See the Pen Preview Easing: EaseInSineChristmasTree by Tohl SMALLFIELD (@tsmallfield) on CodePen.

2) jQuery.animate() + 自作イージング関数

See the Pen Preview Easing: EaseInSineChristmasTree + jQuery.animate() by Tohl SMALLFIELD (@tsmallfield) on CodePen.

3) gsap.fromTo() + 自作イージング関数

See the Pen Preview Easing: EaseInSineChristmasTree + gsap.fromTo() by Tohl SMALLFIELD (@tsmallfield) on CodePen.

じゃじゃ馬ですね。。

EaseOutSineChristmasTree

「Out」だと。。

See the Pen Drawing Easing Curve: EaseOutSineChristmasTree by Tohl SMALLFIELD (@tsmallfield) on CodePen.

EaseInOutSineChristmasTree

「InOut」だと。。

See the Pen Drawing Easing Curve: EaseInOutSineChristmasTree by Tohl SMALLFIELD (@tsmallfield) on CodePen.

EaseOutQuartChristmasTree

jQuery.easing の easeOutQuart を使うと。。

See the Pen Drawing Easing Curve: EaseOutQuartJQueryEasingChristmasTree by Tohl SMALLFIELD (@tsmallfield) on CodePen.

串にささった鏡餅にも見えてきました。

EaseInBounceChristmasTree

GSAPの Bounce.easeIn を使うと。。

See the Pen Drawing Easing Curve: EaseOutElasicGSAPChristmasTree by Tohl SMALLFIELD (@tsmallfield) on CodePen.

もうなにがなんだかわかりません。

まとめ

いかがでしたでしょうか?

既存のイージングだけでは細かいニュアンスを表現できないこともあるかと思います。

そんなときは

イージング関数のパラメータを調整したり、

もしくは0から自作したりしてみてください。

既存のイージング関数をいくつか足したり掛けたりしても面白いかもしれません。

表現の幅が広がります。

それでは良いクリスマスを!

参考リンク

robertpenner.com

easings.net

design.kayac.com

これを読んだお前はCyberpunkに到達し、ナイトシティに火をつける。

はじめに

『2077年の犯罪の定義とは、捕まる事さ。』

キアヌ・リーブスが悪びれもせずにこう言い放つ。

その瞬間、死んで冷たくなっていた<FLAT-LINED>俺の心臓は、AEDによるインパクトをもらった時のように飛び起きた。

そう、去る2.0.2.0.・・・

サイバーパンクの歴史を塗り替える伝説のサイバーパンク「Cyberpunk2077」がとうとう発売されたこの年、世界中の千葉シティが歓喜の渦に包まれたという。

www.spike-chunsoft.co.jp

(うろ覚えで内容不正確かもしれないが、)確か2.0.1.3.にティーザームービーが発表され、2.0.1.8.に発売するつもりが延期になり、2年後の9月に発売するつもりが延期になり、その顛末が散々インターネットでいじられ倒された後、ようやくローンチを迎えたこの作品を心待ちにしていたコンピュータ・カウボーイは数知れない。少なくとも両手では数えきれないほどはいたはずだ。

俺も当然そんな中の一人で、このような自家製のサイバーパンクを作っては、満たされない心のキアヌを慰めていた。

しかし、Cyberpunk2077の発売は成し遂げられ、全世界が熱狂した・・・

そして俺が勤める弊コーポ、つまりカヤック・・・

そこの後輩FUJISAWAは、喜びのあまり古都鎌倉をロボットレストランみたいにギラギラさせるなどして、爆発寸前の感情をインターネットにぶつけていたらしい。

ならばこの俺も、この記念的な瞬間に、祝杯としてのサイバーパンクを捧げる必要がある・・・

だからここにウェブ=ログを残す事にした、というわけだ。

自己紹介

...おっと、自己紹介が遅れたな。

私、クライアントワーク事業部でUnityエンジニアとして働かせて頂いております、井上宗汰と申します。弊社では社員を紹介するサイトがありますが、ここでの情報を元に所在地を特定されると電脳を灼かれる危険性がある為載せておりません。

あ、この記事は Tech KAYAC Advent Calendar 2020 23日目の記事です。

さて。

俺は何者にも縛られないアウトローになりたいし、硬派なハードボイルドでありたいと常に考えているが、だからと言ってほんとに前科者になるのはとても良くないことも知っている。

そこで、逮捕された時の写真っぽい映像が取れるARアプリの試作品を試作した。

実装はARFoundationのPeopleOcclusionを用いてUnityで行った。

こういうのはマグショットっていうらしい。

アメリカで捕まったらマグショットを撮る、ということをユージュアルサスペクツのDVDジャケで学び、最高にクールだと感じたので、コンソールを叩いてプログラミングした。(ちなみに背景画像は「いらすとや」さんでお借りした。いらすとやさんはなんでもあってとてもすごい。)

しかし、今のままだといささかサイバーパンクと呼ぶには物足りない。

そもそもサイバーパンクというものは、技術の発展は人類を明るい未来へ導くことはなく、

むしろ人間の退廃性を加速させ...

超絶圧倒的格差社会の闇が深まり...

そして何より必要なのは、赤とか青とかのライトで紫色に光る人間が鉄砲とか刀とかを持って大暴れする...

そういう合成調味料のようなアクの強さが、サイバーパンクと呼ばれるような作品に求められるのだ。

つまり、このアプリは『サイバーパンク色』に輝いていない...

今回のヤマは、この逮捕体験を赤とか青とかに光らせて、このコンテンツが持つサイバーパンク性を高める事に他ならない。

俺はコンソールを開き、プログラミングを頑張る事にした。

実装について

Unityを触ったことがある人なら恐らく知っていると思うが、UnityにはPostProcessingStackという、お手軽にブルームエフェクトや色調調整をかけることができるライブラリが存在している。大抵のことはデフォルトのColorGradingで事足りると思うが、今回はせっかくなので自作のエフェクトを作って使えるような手順を踏んで、実際に使ってみる。

PPSそのものの基本的な使い方に関してはスコープ外とするので割愛する。マニュアルで紹介されてるGrayscale.csとGrayscale.shaderを踏襲しつつ、

docs.unity3d.com

作成した用意したのはこの2つのファイル。

//Cyberpunk.cs(PostProcessEffectSettingsを継承している方の名前を使わないといけないので注意!!)

using System;
using UnityEngine;
using UnityEngine.Rendering.PostProcessing;


[Serializable]
[PostProcess(typeof(CyberpunkRenderer), PostProcessEvent.AfterStack, "Custom/Cyberpunk")]
public sealed class Cyberpunk : PostProcessEffectSettings
{
    [Range(1f, 10f), Tooltip("Cyberpunk Effect Intensity")]
    public FloatParameter speed = new FloatParameter { value = 1f };
}

public sealed class CyberpunkRenderer : PostProcessEffectRenderer<Cyberpunk>
{
    public override void Render(PostProcessRenderContext context)
    {
        var sheet = context.propertySheets.Get(Shader.Find("Hidden/Custom/Cyberpunk"));
        sheet.properties.SetFloat("_Speed", settings.speed);
        context.command.BlitFullscreenTriangle(context.source, context.destination, sheet, 0);
    }
}
//Cyberpunk.shader

Shader "Hidden/Custom/Cyberpunk"
{
    HLSLINCLUDE

        #include "Packages/com.unity.postprocessing/PostProcessing/Shaders/StdLib.hlsl"

        TEXTURE2D_SAMPLER2D(_MainTex, sampler_MainTex);
        float _Speed;

        float4 Frag(VaryingsDefault i) : SV_Target
        {
            float4 color = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord);

            float displacementAmount = _SinTime.x * _CosTime.y * 0.3;
            color.rgb = color.rgb * float3(i.texcoord.x + displacementAmount, 0, i.texcoord.y + displacementAmount) * 1.2;
            return color;   
        }

    ENDHLSL

    SubShader
    {
        Cull Off ZWrite Off ZTest Always

        Pass
        {
            HLSLPROGRAM

                #pragma vertex VertDefault
                #pragma fragment Frag

            ENDHLSL
        }
    }
}

Cyberpunk.csはPPSで自作シェーダーを使う為に必要なやつで、Cyberpunk.shaderは実際に赤とか青とかに光らせる為に必要な自作シェーダーだ。とりあえず、uv座標をRGBのRとBにぶち込むと画面がサイバーパンクになる事を俺は知っていたので、適当にゆらゆら揺れそうな変数(displacementAmount)を混ぜて適用してみた。

ここで注意点が2つある。

(参考にさせて頂いたのはこの記事様です。ありがとうございます。)

ssr-maguro.hatenablog.com

1つは、PPSの設定用csファイルを作成する時にはPostProcessEffectSettingsを継承した方のクラス名を使う必要があるという事。なんかマニュアルにそう書いてたので、俺はそうした。パンクな姿勢そのものはクールかもしれないが、無意味な逆張りは時間をいたずらに浪費するだけの愚策だ。

f:id:xabutoon:20201223082941p:plain

もう一つの注意点は、自作シェーダーをPlayerSettings/Graphics/AlwaysIncludedShaderに含めないと、ビルド時に反映されない、という事だ。もしくはResourcesフォルダを作ってそこに入れておく、という方法もあるが、俺は今回使ってないので実際動作がどうなるかはわからない。

f:id:xabutoon:20201223083336p:plain

以上の点を踏まえてファイルを作成すれば、

f:id:xabutoon:20201223083609p:plain

f:id:xabutoon:20201223083631p:plain

このようにPost-process Volumeコンポーネントから自作エフェクトを追加できるようになる。

ビルドしてみた結果が、これだ。

2077年のアメリカで逮捕されたような、ギラついた危なっかしさが演出され、俺はまさにサイバネティックなアウトローへと変貌を遂げた。昔ビューティコロシアムという番組があったが、俺はこのBefore/Afterをもって出場資格があると言えるだろう...

エピローグ

...2077年。資本主義の傀儡と化した警察に捕まった俺は、謎の人物が提供した莫大な保釈金によって留置所から放り出された。

呆け顔で空を見上げる俺の寸分先、ダダ漏れ縦ノリミュージックと共に、一台の車が停車した。

ドアが開き、現れたのは伝説のサイバーパンク、キアヌ・リーブスその人だった。

そう、例の保釈金を払ったのはこの男だ。俺をデカいヤマに誘う/もしくは捨て駒にする為に。

無法者としてのキャリアをスタートしたばかりの俺は、導かれるまま車の後部座席に乗り、ネオン煌びやかな闇の中へ溶けて消えた。

おしまい