I wanted to share this asset with you: Simple Interactive Water for URP VR by simplestar-game #UnityAssetStore https://assetstore.unity.com/packages/2d/textures-materials/water/simple-interactive-water-for-urp-vr-162033
良い日でした!
I wanted to share this asset with you: Simple Interactive Water for URP VR by simplestar-game #UnityAssetStore https://assetstore.unity.com/packages/2d/textures-materials/water/simple-interactive-water-for-urp-vr-162033
良い日でした!
Unity Asset Store に例のを提出したんだけど、リジェクトされてしまった。
どうも初回投稿なら、技術力を見せるサイトを持ってないとダメな様子
仕方なく、作ることにします。
とりあえず index.html にアセットの画像がごろごろあればいいんかな
Web サイトか…
今なら React x Typescript かな?
ということで node パッケージマネージャーを使えるようにしましょう。
Windows 環境はインストーラから入れるなど
nodejs.org
こちらの技術書を読んで、サンプルを動かしながらコードを理解してみる
oukayuka.booth.pm
typescript で、見ただけでデータの動きがアニメで見えることが大事
以下のような単語で絵が動けばいい
分割代入
スプレッド演算子
読み切れば Redux + Saga の概念の理解と関数コンポーネントによる React の具体的実装がわかる
https://unityassets.elastprism.com/
具体的な手順はこちら
qiita.com
1.yarn build でできた build フォルダの中身を S3 にアップロード
2.Cloudfront でディストリビューションを作って、データオリジンに S3 を選ぶ
参考記事
simplestar-tech.hatenablog.com
3.バージニア北部にドメイン指定で証明書を作る
4.Route53で独自ドメインからCloudfrontへのAlias作る
以上の手順で世界からの独自ドメインリクエストするとCloudfrontへルートができて、各エッジサーバーからReact の SPA のアクセスが有効になる
肝となるのが、上記の Qiita の紹介にあるとおり Cloudfront の Custom Error Response で /index.html を 403 や 404 のときに返すようにする
これで、どの Route 先ページでも F5 でリロードしても S3 アクセス拒否という 403 エラーは返ってこない
そういえば昔ホームページの作り方を書いたことあったけど5年もすると Cloudfront で SPA を配信できるようになる(腕を上げたな)
simplestar-tech.hatenablog.com
ところでアセット紹介ページがまだぜんぜん形になってないのです。
追記:
単純に yarn build の成果物を公開すると .map ファイルが同梱されるためソース内容(ts, tsx)実装が同時に公開されてしまいます。
.env ファイルを直下に置いて
GENERATE_SOURCEMAP=false
を書き込んでから yarn build することで without sourcemap で build でき、それを公開した場合は実装がばれずに公開することができました。
情報元はこちら
qiita.com
先月、こちらに登壇して PlayFab の CloudScript で同時実行を回避しつつ、不正させないゲームのためのアイディアを語ってみたのですが
jpfug.connpass.com
質問者から CloudScript が実行されている場所って US West オレゴンだから、日本にキャッシュサーバー置くと
結果的に情報路が長くなって、片道 1.3万キロメートルだから、理論上通信に最小 0.1 秒ほどの不要な遅れが足されて
あと日本でサーバー立てる方がランニングコストも通信費も高いですよね
とご指摘いただいたのです。
なるほど、go言語キャッシュサーバーを US West オレゴンに置いて、そこにアクセスする CloudScript も用意して
実際の通信速度に差が 0.1 秒ほど出るのか試してみますね!
以前行った時のログをたよりにドキュメントを読み直し 東京リージョンと同じ構成でオレゴンリージョンにも同じ golang キャッシュサーバーを構築します。
simplestar-tech.hatenablog.com
まず、自宅(日本、東京)の pc からリクエストをそれぞれの golang サーバーに送ってヘルスチェックレスポンスが返ってくるまでの時間を計測
東京リージョンは 110~180 ms を要してました。
オレゴンリージョンは 610~680 ms を要してました。
この、それぞれのサーバーにヘルスチェックリクエストをする PlayFab CloudScript を javascript で実装し
自宅(日本、東京)の pc 上で実行する Unity クライアントから、CloudScript を呼び出してヘルスチェックレスポンスが返ってくるまでの時間を計測しました。
東京リージョンは 650~700 ms を要してました。
オレゴンリージョンは 220~300 ms を要してました。
日本・東京の Unity クライアントから、PlayFab CloudScript を呼び出して golang のキャッシュサーバーのレスポンスを確認して Unity に戻ってくるまでの時間を計測しました。
サーバーの場所:
東京リージョンは 650~700 ms を要してました。
オレゴンリージョンは 220~300 ms を要してました。
PlayFab の PlayStream には、CloudScript 呼び出しの詳細が json で記録されますが
東京リージョンに置いた golang キャッシュサーバーにヘルスチェックを返してもらうのに "ExecutionTimeSeconds": 0.5307192
オレゴンリージョンに置いた golang キャッシュサーバーにヘルスチェックを返してもらうのに "ExecutionTimeSeconds": 0.0244125
PlayFab のスタジオのリージョンを日本にできればいいんだけどね…オレゴンにあるのは間違いない
今は東京リージョンにキャッシュサーバーを置くのは間違い確定なので、しばらくオレゴンリージョンに置いて作業を進めます。
アクションを束ねた、アクションセットを作成するところから始まります。
最初はいくつものアクションが定義された default アクションセットが選択されている
default のほかに platformer, buggy, mixedreality のアクションセットが確認できる
Window > Steam VR Input でダイアログを表示し
既存の default, platformer, buggy, misedreality のボタンの右側に + ボタンあるので押す
NewSet で作成、何か一つ In Actions に NewAction を追加 boolean Type とする
Save and generate ボタンを押し、完了を待つ
using UnityEngine; using Valve.VR; public class MyActionScript : MonoBehaviour { // a reference to the action public SteamVR_Action_Boolean sphereOnOff; // a reference to the hand public SteamVR_Input_Sources handType; //reference to the sphere public GameObject sphere; void Start() { this.sphereOnOff.AddOnStateDownListener(this.TriggerDown, handType); this.sphereOnOff.AddOnStateUpListener(this.TriggerUp, handType); } private void TriggerDown(SteamVR_Action_Boolean fromAction, SteamVR_Input_Sources fromSource) { Debug.Log("Trigger is down"); this.sphere.GetComponent<MeshRenderer>().enabled = true; } private void TriggerUp(SteamVR_Action_Boolean fromAction, SteamVR_Input_Sources fromSource) { Debug.Log("Trigger is up"); this.sphere.GetComponent<MeshRenderer>().enabled = false; } }
ということ
自分で作ったアクションセットはゲーム開始時にアクティブではない
アクティブになるように明示
先ほどの MyActionScript より前に実行される位置にシーンに配置しないといけない制約もある
Window > Steam VR Input でダイアログを表示し、Open Binding UI ボタンを押す
newset という、さっき作ったアクションセットのタブが見える。
アクションが割り当たっていないことを示す表示かな
タブを選択して
まとめると、以下の一つが欠けると、何も反応ない結果になる
Unity でゲーム作っている人なら多くの方が知っている VRM - VR向け3Dアバターファイルフォーマット -。
その VRM の標準シェーダーとして採用されている MToon を URP でも表示できるようにしたい!
作りましょう!
そのための情報集めから作業をこの記事で公開します。
そのあと、公開しました。
github.com
新しく ShaderGraph - Unlit を作成して公開パラメータとして次のものを作成します。
github.com
ここにあるサブグラフ一式と .hlsl シェーダー実装をコピーしておきます。いつでも使えるように
内容はほんと、単に光源情報取ってきているだけです。
次の動画の説明欄にあるリンクから Toon 表現の肝となる Node を見つけてコピーします。
ほしいのはこの Node です。
そして MToon で外せないのが Outline です。
Shader Graph で実現する方法が紹介されている記事がこちら
Normal が Alpha テストできない問題に最終的に当たるので、もろもろ削除して、結局 Depth を書き出すプロジェクトで次の CustomFunction を呼ぶだけにします。
最終的に Outline サブシェーダーを作りますが、そこに登場する Custom Function は三つ
下図のとおり、左上のオフセットが
Out = unity_StereoEyeIndex;
左下の係数が
Out = 1.0; #if UNITY_SINGLE_PASS_STEREO Out = 0.5; #endif
右下の Custom Function がこちら
TEXTURE2D(_CameraDepthTexture); SAMPLER(sampler_CameraDepthTexture); float4 _CameraDepthTexture_TexelSize; void OutlineObject_float(float2 UV, float OutlineThickness, float DepthSensitivity, float NormalsSensitivity, out float Out) { float halfScaleFloor = floor(OutlineThickness * 0.5); float halfScaleCeil = ceil(OutlineThickness * 0.5); float2 uvSamples[4]; float depthSamples[4]; uvSamples[0] = UV - float2(_CameraDepthTexture_TexelSize.x, _CameraDepthTexture_TexelSize.y) * halfScaleFloor; uvSamples[1] = UV + float2(_CameraDepthTexture_TexelSize.x, _CameraDepthTexture_TexelSize.y) * halfScaleCeil; uvSamples[2] = UV + float2(_CameraDepthTexture_TexelSize.x * halfScaleCeil, -_CameraDepthTexture_TexelSize.y * halfScaleFloor); uvSamples[3] = UV + float2(-_CameraDepthTexture_TexelSize.x * halfScaleFloor, _CameraDepthTexture_TexelSize.y * halfScaleCeil); for(int i = 0; i < 4 ; i++) { depthSamples[i] = SAMPLE_TEXTURE2D(_CameraDepthTexture, sampler_CameraDepthTexture, uvSamples[i]).r; } // Depth float depthFiniteDifference0 = depthSamples[1] - depthSamples[0]; float depthFiniteDifference1 = depthSamples[3] - depthSamples[2]; float edgeDepth = sqrt(pow(depthFiniteDifference0, 2) + pow(depthFiniteDifference1, 2)) * 100; float depthThreshold = (1/DepthSensitivity) * depthSamples[0]; Out = edgeDepth > depthThreshold ? 1 : 0; }
Toon 表現と Outline がそろっているので、接続して MToon の説明をたよりに編みます
MToon の心臓となる処理は Main と Shade のテクスチャを陰影で利用すること。
なので、Toon 表現で白黒を出力して、それを Lerp する処理が書けたらほぼ完成。自分はさらにライト色をもらうように Multiplyしてます。
最後に塩コショウのように Sphere Add と Emission を足すと
キューブの見た目を更新する目的で動いています。
前回は Shader ができたところまで
simplestar-tech.hatenablog.com
今回はテクスチャを連番で結合する処理を作ります。
大分前に python の pillow で画像処理を書きましたが…
github.com
処理が遅すぎるのと
画像のエッジの引き延ばしを行っていなかったので、キューブ群を遠目で見ると結合部分が光ったり黒くなったり…とにかく見た目が良くない
その部分を今回は imagemagick を利用して解決していきます。
参考までに、昔のキューブの見た目は頑張ってこんなの
simplestar-tech.hatenablog.com
もう2年以上、技術選定を続けているという…今年は完成させるぞ!
simplestar-tech.hatenablog.com
まずは Windows 環境で使えるように portable 版をダウンロードして展開し PATH を通しておきます。
imagemagick.org
以降、Windows 環境だと convert コマンドを magick にしなければバッティングする旨を imagemagick が教えてくれるので
magick コマンドを利用します。
そうしたことを念頭に次のマニュアルを完走して、imagemagick を身体になじませました。
情報ソースはこちら
www.imagemagick.org
細かいことは置いとくと、次の倍率を指定するだけで余白を引き延ばすことができます。
(残念ながら distort は基本操作には出てこない)
magick in.png -set option:distort:viewport %[fx:w*(1+0.05)]x%[fx:h*(1+0.05)] -virtual-pixel Edge -distort SRT "0,0 1,1 0 %[fx:w/(2/0.05)],%[fx:h/(2/0.05)]" out.png
ちょっとだけ解説すると
distort:vieport が left, top 引き延ばし幅に関与&全体の幅高さ倍率指定
virtual^pixel Edge が right, bottom の引き延ばし幅に関与していて、要するに 1 引いた倍率を 1/2 倍で指定というながれ
変換した画像を利用するという小技について、まずはおさらい。
こちらの画像を入力に(昔、自分が描いた絵です)
こちらの処理を実行すると
magick in.jpg -resize 200x200 -size 300x300 xc:blue +swap -gravity center -compose over -composite -mattecolor red -frame 10x10 exit.jpg
意味は、200x200 にアスペクト比を保ったまま縮小して、blue 一色で塗りつぶした 300x300 の画像を新規作成、並び順を入れ替えて、conposite により青を背景に重ね合わせて、10pixel 幅の赤いフレームを追加
という文(読めました?)
次の結果が得られます。
以下の powershell は Windows 環境で imagemagick に PATH が通っていれば動きます。
テクスチャはこちらの有料アセット(single entity license)を購入したものを利用します。
Yughues PBR Nature Materials
assetstore.unity.com
tga ファイルは magick で変換すると上下逆転しますし、Specular は png に tga から変換すると背景色が真っ白に変わるので(本当は黒)
一度 jpg に中間ファイルを出して、上下反転しつつもなんとか
あと、ファイルによっては正方形ではないので正方形に直します。
加えて、左右に 8 pixel の余白を設けるように 1008 x 1008 に圧縮してタイリングしたいと思います。
を実現する Powershell が以下の通り
# [AO, Diffuse, Height, Normal, Specular] $target = "Specular" New-Item $target -ItemType Directory -Force $dir = "~\Assets\Yughues PBS Nature Materials" $imgs = Get-ChildItem -Recurse -Path "$dir\*$target.tga" foreach ($img in $imgs) { $fullName = $img.FullName $jpg = "$target\" + [io.path]::ChangeExtension($img.Name, "jpg") $id = identify $fullName $edge = 0.0158730 if ($id -like "*512x1024*") { magick $fullName -resize 504x1008 -flip -write mpr:i +delete mpr:i mpr:i +append -set option:distort:viewport "%[fx:w*(1+$edge)]x%[fx:h*(1+$edge)]" -virtual-pixel Edge -distort SRT "0,0 1,1 0 %[fx:w/(2/$edge)],%[fx:h/(2/$edge)]" -quality 100 $jpg } else { magick $fullName -resize 1008x1008 -flip -set option:distort:viewport "%[fx:w*(1+$edge)]x%[fx:h*(1+$edge)]" -virtual-pixel Edge -distort SRT "0,0 1,1 0 %[fx:w/(2/$edge)],%[fx:h/(2/$edge)]" -quality 100 $jpg } echo $jpg } montage "$target\*$target.jpg" -tile 8x8 -geometry 1024x1024 "0_$target.png"
出力されるテクスチャを使って、Height map を利用しつつ絵を作ることができました。
ステップ2はクリアです。
残すはゲーム内の UV 操作のみ
余白をエッジ引き延ばしするのもよかった
だけど parallax で使う場合はかなり余白を利用することになるし、そこがエッジ引き延ばしだとまた不自然な見た目になったので
リピートラッピングする方法を考案しました。
次の命令は画像の上下左右ななめ方向すべてにタイリングする例です
magick in.jpg -resize 960x960 -flip -write mpr:i +delete mpr:i mpr:i mpr:i +append -write mpr:j +delete mpr:j mpr:j mpr:j -append -gravity center -crop 1024x1024+0+0 -quality 100 out.jpg
これをスクリプトにつなげると
# [AO, Diffuse, Height, Normal, Specular] $target = "Diffuse" New-Item $target -ItemType Directory -Force $dir = "D:\github\Unity\UniversalParallaxOffset\Assets\Yughues PBS Nature Materials" $imgs = Get-ChildItem -Recurse -Path "$dir\*$target.tga" foreach ($img in $imgs) { $fullName = $img.FullName $jpg = "$target\" + [io.path]::ChangeExtension($img.Name, "jpg") $id = identify $fullName if ($id -like "*512x1024*") { magick $fullName -resize 480x960 -flip -write mpr:i +delete mpr:i mpr:i +append -write mpr:j +delete mpr:j mpr:j mpr:j +append -write mpr:k +delete mpr:k mpr:k mpr:k -append -gravity center -crop 1024x1024+0+0 -quality 100 $jpg } else { magick $fullName -resize 960x960 -flip -write mpr:j +delete mpr:j mpr:j mpr:j +append -write mpr:k +delete mpr:k mpr:k mpr:k -append -gravity center -crop 1024x1024+0+0 -quality 100 $jpg } echo $jpg } montage "$target\*$target.jpg" -tile 8x8 -geometry 1024x1024 "0_$target.png"
期待通り