takeyohのおぼえがき

気になったこと、試したことの記録です。

InstaLODでLodファイルの作成を試みる!

ずっと愛用していたSIMPLYGONですが、2024/3/31を持って無料ライセンスが無くなってしまいました。
じゃ、どうやってLodB~LodDのkn5を作ればよいのか・・・?で悩みましたが、同じようにポリゴン数を減らして軽量化することが出来るInstaLODなるソフトウェアが存在することを知りました。
これまた多機能で、使い方は全くわかりませんが、何とかLodの作成はできそうでしたので、忘れないうちに覚書。
まずInstaLODですが、こちらは個人向けの無料ライセンスがあります。(いつまで存在するかはまた不安ですが)
そして、InstaLODのインストール方法は省略します。(アカウント作成、ライセンス購入(無用)、クラウドにログイン、アプリダウンロード、インストールの順です。)

では、LODの作成方法で。

まず、LodAにあたる元のモデルをblnederで表示します。
次に、InstaLODへインポートするためのfbxを作成します。
いつものfbxとちょっと違います。

エンプティとメッシュとその他を選択し、前方がZ、アニメーションをベイクはオフ、これらはいつもと一緒ですが、
スケールは1のままにします。(0.01にはしない)
で、適当な名前でfbxファイルをエクスポートします。(ここではtest.fbxにしました)

続いて、InstaLODを起動。

Create a new InstaLOD profileを選択。


一番上のOptimizeを選択して「Create Profile]をクリック。


メニューの右側にMesh Operation Settingsというタブが表示されていない場合は、タブの空欄で右クリックし、出てきたメニューからMesh Operation Settingsをクリックします。
すると下記のようなメニューが表示されます。

続いて、先ほど作成したfbx(ここではtext.fbx)をインポートします。
FileからOpen Sceneでも可能ですが、フォルダからtext.fbxを直接ドラッグ&ドロップでもOKです。

インポートされると、車(今回はバイクですが)が真ん中に表示され、メッシュやノードの構造が左にツリー上に表示されます。

次に、この3dモデルのポリゴン数を削減していきます。
右Mesh Operation SettingタブのOptimizeメニューのOptimize Settingsで、Percent Trianglesを選択し、数値を20くらいにします。(デフォルトは50)
これは、元のモデルからどれくらいポリゴンを削減した状態にするかを指定しているようです。20だとポリゴンの数が20%(80%減)になります。

今回のバイクmodの場合は、LodAで57万ポリゴンくらいでしたが、ここからLodBの場合は20%、LodCの場合は2%、LodDの場合は0.5%くらいに設定しました。
LodBを例に続けます。(LodCもLodDも基本同じ)

Percent trianglesを設定したら、左上の「Start」をクリックすると処理が始まります。(少し待つ)
処理が終わるとこんな感じです。Total Polygonsがかなり削減されているのがわかります。

でも、20%設定くらいでは、モデルもそれほど劣化しません。(結構すごいですね。)

FileメニューのExport Sceneを選択し、fbxをエクスポートします。

ファイル名(ここではgsx750_lodb.fbx)を設定して、Type はDefaultのまま、Saveをクリックして保存します。
このままではまだlodファイルとして使えません。
新規でblenderを起動し、エクスポートしたgsx750_lodb.fbxをインポートします。
スケールは1、前方は-z(マイナスz)にしてインポートします。

lodBのモデルがインポートされます。ここで不要なノードやメッシュがあればついでに削除すればさらに軽量化できるかもしれません。
あと、InstaLODで変換処理を行った際、オブジェクトの名前の後ろに「_Default」が追加されています。
これが邪魔なので、blenderの編集メニューから、「名前を一括変更」を選択します。

続いて「全て」を選択し、検索に「_Default」と入力し、OKを押します。すると、すべてのオブジェクト名から_Defaultの文字が消えます。
この状態で、いつも通りのfbxエクスポートをします。
今回は先ほどのgsx750_lodb.fbxを上書きしてエクスポートしました。(スケールは0.01、前方はz(プラスz)です。)

続いて、lodb用の設定ファイルを作成します。
lodA用の設定ファイル(今回の例ではgsx750.fbx.ini)をコピーしてファイル名をgsx750_lodb.fbx.iniにします。
(拡張子が非表示設定になっている人は拡張子を表示するように設定変更しておきましょう。)

gsc750_lodb.fbx.iniを開くと、前半にマテリアルの設定、後半にノードやメッシュの設定が入っています。
一番わかりやすい方法としては、このiniファイルをメモ帳とかで開いて、一番下まで移動します。
[model_FBX: gsx750.fbx_bike_plateM....のようにmodelで始まるセクションがあると思います。

この、FBX:の後ろからgsx750.fbxの部分までをfbxのファイル名に合わせます。
gsx750.fbxの部分を範囲選択して、メモ帳の編集から置換を選択します。
検索文字(上の欄)には範囲選択した文字列が入っていると思います。
置換文字(下の欄)に、lodBのfbxファイル名(ここではgsx750_lodb.fbx)と入力し、すべて置換を選択し、置換出来たら保存します。

ここまで順調にいけば、あとはksEditorです。
ksEditorを起動し、lodBのfbxを開きます。
iniファイルが正しく編集できていれば、lodAと同じ設定がすでにされた状態になっています。
ただ、ガラスなどのような透過させているオブジェクトのtransperent設定が消えていることがあるので、Materialsタブから、ガラスなど透過させるマテリアルを選択し、右のtransparent ONをクリックすると、このマテリアルが設定されたオブジェクト全てが透過設定されます。

最後に、FileタブからSave KK5を選択、Car(No Textures)を選択して、kn5を生成します。(今回だとgsx750_lodb.kn5)
生成したlodB用kn5(gsx750_lodb.kn5)をcar modフォルダの直下にコピーします。
dataフォルダのlods.iniでlodBのkn5を設定します。
今回は、上記を同様の手順でlodC、lodDのkn5も作成して、以下の様にlods.iniを設定しています。

[COCKPIT_HR]
DISTANCE_SWITCH=7

[DRIVER_HR]
DISTANCE_SWITCH=7

[LOD_0]
FILE=gsx750.kn5
IN=0
OUT=15

[LOD_1]
IN=15
OUT=45
FILE=gsx750_lodb.kn5

[LOD_2]
IN=45
OUT=201
FILE=gsx750_lodc.kn5

[LOD_3]
IN=201
OUT=2000
FILE=gsx750_lodd.kn5

car modとカメラ視点との距離がIN,OUTの間にあると該当するkn5が表示されます。
ゲーム中、15mまではlod_0、15mから45mまではlod_1・・・のように表示されるkn5が切り替わります。
(これによって、遠くにいる車は軽量なkn5を表示させることで、ゲーム自体の負荷を軽減させています。)

InstaLODを使ったlodB~lodDの作り方は以上です。
(忘れないうちに書いておこうと必死・・・)

Content Managerで自動生成できていたのは便利だったんですけどねぇ。今後Content Managerは何を選択していくんでしょうね?

アニメーションを速度やRPMに合わせてシームレスに動かす。

例えば、自転車のmodでもそうでしたが、タイヤ以外のアニメーション、ペダルや足の動きは、スピードやRPMに合わせて再生速度を変えることができなかったため、速度やRPMを4段階くらいに分けて、各レンジごとにloop再生速度を変えて表現していました。
これでも良いと言えばよいのですが、やはりスピードやRPMに合わせてシームレスにアニメーションしてほしいですよね。
今回そのやり方を教えていただき、いろいろテストした結果、ようやく実装できたので、その覚書です。

まず、今回の方法はext_config.iniのANIMATIONで設定できるものであれば、car mod側でもドライバ側でもどちらにも対応できます。
ただし、ドライバのアニメーション制御については、animationsフォルダにsteer.ksanimが存在する場合うまく制御できません。
このため、もしステアリングやシフトチェンジ以外のアニメーションをドライバにさせたい場合(そんな機会あまりないかもしれませんが)、
steer.ksanimを別名にして、下記の制御に一緒に組み込む必要があります。

まず、extensionフォルダのext_config.iniにlua scriptを読み込む設定を追加します。

[SCRIPT_...]
SCRIPT="leg.lua"
SKIP_FRAMES = 0
ACTIVE_FOR_NEAREST=20
ACTIVE_FOR_UNFOCUSED=1

ACTIVE_FOR_UNFOCUSED=1を設定すると、リプレイ時に車から遠ざかっても、アニメーションが継続されます。
これを設定しないと、20m離れたところでスクリプトは動かなくなります。
車内のアニメーションとかならそれの方が処理も軽くて良いのですが、今回足のアニメーションは外からもろ見えるので距離が離れてもアニメーションが動くように設定しています。
ACTIVE_FOR_NEAREST=20は、AI車として使った場合、自車から見て20台以内に入るとスクリプトが動くというものです。
AI車として使っても動くようにするためには、この設定が必要ですね。

スクリプト名は何でもよいです。今回は椅子modのドライバの足のアニメーションを例にするので、leg.luaという名前になってます。
で、足のアニメーションはanimationsフォルダにleg.ksanimとして保存しています。
また、椅子modはハンドリングが無いので、steer.ksanimは削除しています。

つづいて、extensionフォルダにleg.luaを作成して以下を追記します。

local legAnimFile = "../animations/leg.ksanim"
local progress = 0
local driverRoot = ac.findNodes('DRIVER:DRIVER')

function script.update(dt)
    progress = (progress + dt * ac.getCar().speedKmh/10) % 1
        driverRoot:setAnimation(legAnimFile,progress,false)
end

1行目がアニメーションファイルの場所
2行目はアニメーションの進捗率(0~1)。初期値として0を設定。
3行目がアニメーションを反映させるノード(エンプティ)を指定。ドライバの場合はDRIVER:DRIVERになります。
(car modの場合は、アニメーションを設定しているエンプティ名で指定します。)
4行目以降がアニメーションの制御部分。
5行目がアニメーションの進捗率の計算です。この計算にspeedKmhやRPMを組み込むことで、それらの値に連動した制御が可能になります。
ただし、アニメーションは何秒間という設定ではなく、一つの周期が0~1で制御されています。
%1(1で割った余り)を代入することで、0~1をループするようになります。
6行目がアニメーションの設定。アニメーションのループスピードを変更するのではなく、アニメーションの進み度合いをprogressで都度設定して制御しています。
これは目から鱗な方法です。なるほどね~。

今回の例では、ドライバの足のアニメーションとなっていますが、同じことを例えばキャタピラとか、バイクのチェーンとか、car modのパーツに対しても適用することが可能ですね。
ただ、メッチャ大変だと思いますけど。(笑)

ac_car_scriptable_displayを活用した音源の操作方法

assettocorsaは、car modの中にsfxフォルダというのがあり、ここに音源に関するbankファイルとその中に入っているイベントのIDが並んだGUIDs.txtというファイルがあります。このbankファイルとGUIDs.txtは2つで一組になります。
GUIDs.txtに記載されている
event:/XXXXとなっている行が、bankファイルに格納されている音源の場所を指定しています。
たとえば、event:/cars/(carID)/engine_intは車内視点時用のエンジン音、event:/surfaces/grassだと、草の上を走った時の音、とかそういうことですね。
ゲーム起動時には、AI車両を含め、各車ごとにこの2つの音源ファイルが読み込まれ、車の状態に合わせて、音を制御し出力しています。
その際、車外視点でのボリュームを1とすると、車内視点は0.25(外視点の4分の1)の大きさで再生されるように設定されています。
車の中は気密性が高いから、音が小さくなることを再現しているんですね。

ここまでは、前置きというか前提でして、課題はこれから。
今回S2000を作成し、屋根が開くようにしました。
そうすると、車内視点の音量は、0.25倍ではなく、1倍にしたいわけです。
音量を0.25倍→1倍にするための覚書となります。

まず、音量を調整するのに一番簡単な方法は、luaアプリを使って制御する方法です。
ac.setAudioVolume関数が使えます。

---Sets audio volume for given channel, value from 0 to 1. If channel is not recognized, does nothing.
---@overload fun(value: number)
---@param audioChannelKey ac.AudioChannel
---@param value number @Value from 0 to 1.
---@param carIndex integer? @If set, applies volume as a multiplier to a specific car (currently supported: \`'dirt'\`, \`'engine'\`, \`'opponents'\`, \`'surfaces'\`, \`'transmission'\`, \`'tyres'\`, \`'wind'\`). Default value: -1.
function ac.setAudioVolume(audioChannelKey, value, carIndex) end

audioChannelKeyには音量を変更したいac.AudioChannelのパラメータを入力。

---@alias ac.AudioChannel
---| `ac.AudioChannel.Main` @Value: 'main'.
---| `ac.AudioChannel.Rain` @Value: 'rain'.
---| `ac.AudioChannel.Weather` @Value: 'weather'.
---| `ac.AudioChannel.Track` @Value: 'track'.
---| `ac.AudioChannel.Wipers` @Value: 'wipers'.
---| `ac.AudioChannel.CarComponents` @Value: 'carComponents'.
---| `ac.AudioChannel.Wind` @Value: 'wind'.
---| `ac.AudioChannel.Tyres` @Value: 'tyres'.
---| `ac.AudioChannel.Surfaces` @Value: 'surfaces'.
---| `ac.AudioChannel.Dirt` @Value: 'dirt'.
---| `ac.AudioChannel.Engine` @Value: 'engine'.
---| `ac.AudioChannel.Transmission` @Value: 'transmission'.
---| `ac.AudioChannel.Opponents` @Value: 'opponents'.

たとえば、'main'とか、'engine'とか指定しても良いですし、エイリアスが設定されているので、`ac.AudioChannel.Main`と書いてもよいです。
valueは音量(0~1)、carIndexは対象の車(自車なら0)です。

なのですが、このac.setAudioVolumeという関数は、car modで使えるluaライブラリには含まれていません。
ちょっと脱線ですが、assettocorsaではいろんなところでluaスクリプトが使えますが、それぞれ別々のluaライブラリが設定されており、それを変更することはできません。
(assettocorsaインストールフォルダ)\extension\internal\lua-sdkの下を見ていただくと、ac_で始まるフォルダがいくつかあって、それぞれの中にlib.luaが入っています。
luaアプリで使用されるライブラリはac_appsの下にあるlib.luaですが、car modで使用されるライブラリは、物理制御系ならac_car_cphys、映像、音制御系ならac_car_scriptable_displayが使われます。
で、今回のacAudioChannel関数は、ac_appsのlib.luaには定義されていますが、ac_car_cphysとac_car_scriptable_displayには定義が無いため、使えないということになります。

じゃあ、どうやってcar mod関係のluaスクリプトから、環境音を制御するのか?
代わりにやっと見つけた関数がac.CarAudioTweak.setVolumeです。

>
      • Set volume multiplier. Overrides `[AUDIO_VOLUME]` value from car config.
      • @param eventID ac.CarAudioEventID @ID of a target event.
      • @param value number @New value from 0 to 1 (100%), can go above 1 as well.

function ac.CarAudioTweak.setVolume(eventID, value) end<||
この関数なら、ac_car_scriptable_displayにも定義があるので使えます。
eventIDはac.CarAudioEventIDから指定できます。

>
      • @alias ac.CarAudioEventID
      • | `ac.CarAudioEventID.EngineExt` @Value: 0.
      • | `ac.CarAudioEventID.EngineInt` @Value: 1.
      • | `ac.CarAudioEventID.GearExt` @Value: 2.
      • | `ac.CarAudioEventID.GearInt` @Value: 3.
      • | `ac.CarAudioEventID.Bodywork` @Value: 4.
      • | `ac.CarAudioEventID.Wind` @Value: 5.
      • | `ac.CarAudioEventID.Dirt` @Value: 6.
      • | `ac.CarAudioEventID.Downshift` @Value: 7.
      • | `ac.CarAudioEventID.Horn` @Value: 8.
      • | `ac.CarAudioEventID.GearGrind` @Value: 9.
      • | `ac.CarAudioEventID.BackfireExt` @Value: 10.
      • | `ac.CarAudioEventID.BackfireInt` @Value: 11.
      • | `ac.CarAudioEventID.TractionControlExt` @Value: 12.
      • | `ac.CarAudioEventID.TractionControlInt` @Value: 13.
      • | `ac.CarAudioEventID.Transmission` @Value: 14.
      • | `ac.CarAudioEventID.Limiter` @Value: 15.
      • | `ac.CarAudioEventID.Turbo` @Value: 16.
      • | `ac.CarAudioEventID.WheelLF` @Add 0-based index to this value for Nth wheel.
      • | `ac.CarAudioEventID.WheelRF` @Value: 21.
      • | `ac.CarAudioEventID.WheelLR` @Value: 22.
      • | `ac.CarAudioEventID.WheelRR` @Value: 23.
      • | `ac.CarAudioEventID.SkidIntLF` @Add 0-based index to this value for Nth wheel.
      • | `ac.CarAudioEventID.SkidIntRF` @Value: 31.
      • | `ac.CarAudioEventID.SkidIntLR` @Value: 32.
      • | `ac.CarAudioEventID.SkidIntRR` @Value: 33.
      • | `ac.CarAudioEventID.SkidExtLF` @Add 0-based index to this value for Nth wheel.
      • | `ac.CarAudioEventID.SkidExtRF` @Value: 41.
      • | `ac.CarAudioEventID.SkidExtLR` @Value: 42.
      • | `ac.CarAudioEventID.SkidExtRR` @Value: 43.

<||
valueは0~1を指定できると書かれています。
やってみると、確かに音量を変更することが出来たのですが、ここで新たな問題が。
このvalue0~1の指定は、室内の音量が0.25倍に制御された状態が1なのです。
だから、valueに1を指定するとデフォの0.25倍、valueに0.5を指定するとさらに半分の0.125倍の音量になってしまうのです。
屋根を空けたら、外の音量にしたいわけなので、車内用の音を0.25倍より大きくできないじゃん・・・!

でも、もしかして?と思って、指定を無視し、valueを4に設定してみたところ、なんと反映されました!
元々0.25倍に制御されている音源を4倍にするので、外音源の1倍と同じ音量になりました。

S2000の屋根の開閉に合わせて、エンジン音を変更するスクリプトを例に掲載します。
(実際にはここからさらに手を加えますが、わかりやすいように単純化しています。)

lua >

local roof = false

function update(dt)
if ac.getCar().extraE == true and roof == false then
ac.CarAudioTweak.setVolume(ac.CarAudioEventID.EngineInt,4)
roof = true
end
if ac.getCar().extraE == false and roof == true then
ac.CarAudioTweak.setVolume(ac.CarAudioEventID.EngineInt,1)
roof = false
end
end

extraEキーを押すと、屋根が開くようにアニメーション設定しているので、extraEがtrueになったら、ac.CarAudioEventID.EngineInt(車内用のエンジン音源)の音量を4に、extraEがfalseになったら1に戻すというスクリプトになります。

これで、とりあえずcar modに付随する環境音の音量を制御することはできるようになりますが、track側からの音量の変更はやはりできません。(これは仕方がないか)


あと、ここからは番外編。上記はcar modに設定された車の環境音の音量を制御するための方法ですが、ac_car_scriptable_displayのlib.lua自体には、bankファイルを読み込む機能があります。
ac.loadSoundbank(soundbank, guids) 
ここでloadされた音源データとGUIDS.txtの音源は、ac_car_scriptable_display用のlua script内でも自由に再生・停止させることが可能ですし、音量も簡単に変更できます。今回のS2000でも、ドア開閉時の音はac_car_scriptable_displayのlua script内で、別音源bankファイルをloadして再生・停止を制御しています。

以上です。

画面全体をフェードイン、フェードアウトさせる。

カメラのアングル自動切換えアプリに、AFKモード(操作しない状態に登場するカメラワークのモード)を作りました。
ただ、そのAFKモードはアングルが5種類あるのですが、これが切り替わるたびに画面全体をフェードイン、フェードアウトさせたかったのですが、やり方がわからずチャットで聞いてみたら、あ~るさんが教えてくださいました。あ~るさん、ありがとうございます!
ということで、その実装方法の覚書です。

assettocorsaのCSPにおけるluaアプリでは、callbackという機能がいくつかって、その中のUI callbackを使う手法です。
これは、ゲーム中の画面にフルスクリーンUIを生成する機能・・・だそうです。(公式WIKIより。でも細かいことはよくわからないです。)

実装方法です。
まず、manifest.iniに以下を追記します。

[UI_CALLBACKS]
IN_GAME = fullscreenUI

これで、制御可能なフルスクリーンUIが準備されます。
続いて、luaアプリ側での制御です。今回は、画面全体をフェードイン・アウトさせる機能を実装しました。

local fadeCount = 0
local fadeFlag = "clear"
local screenSize = vec2(ac.getSim().windowWidth,ac.getSim().windowHeight)
function script.fullscreenUI(dt)
  if fadeFlag =="fadeIn" and fadeCount >= 0 then
    fadeCount = fadeCount - dt * 2
  elseif fadeFlag == "fadeOut" and fadeCount <= 1 then
    fadeCount = fadeCount + dt * 2
  elseif fadeFlag == "black" then
    fadeCount = 1    
  elseif fadeFlag == "clear" then
    fadeCount = 0
  end
  if fadeCount > 0 then
    ui.drawRectFilled(vec2(0,0), screenSize,rgbm(0,0,0,fadeCount))
  end
end

先ほど追加したフルスクリーンUI自体の制御は、script.fullscreenUI(dt)という関数で制御します。(4行目)
ここでは、fadeFlagという変数に特定の文字列を入れることで、制御を分岐させています。
3行目は、ゲーム画面のサイズを定義しています。このフルスクリーンUIすべてを埋め尽くす四角を書いて、その透明度を変化させることで、フェードイン、フェードアウトを制御しています。
if文でいろいろ分岐制御(5~13行目)してますが、fadeInなら黒から徐々に明るく、fadeOutなら逆に画面を徐々に黒く、blackなら画面を真っ黒に、clearなら明るくするという制御になります。
15行目が実際の四角を表示している部分です。
前後のif文はclear(暗くしない)状態では、画面いっぱいの四角自体を表示しないようにするためです。
大した変化はないと思いますが、一応負荷軽減のための策です。(^^;

以上です。
実際にフェードイン・アウトしている様子はこちら。
youtu.be

車によってフォースフィードバック(FFB)が効かなくなる症状の改善方法

何が原因でこうなるのかはわからないのですが、一律ではなく、車(car mod)によって、フォースフィードバック(FFB)が全く効かなくなる症状が出ました。
その覚書です。

車によってFFBが効くものと、効かないものがあるので、最初は車の設定(特にdataフォルダの中)が怪しいと思い、FFBが効いている車のdataフォルダを移植したりして試しましたが、改善しなかった・・・と。
で、FFBが効かない車のフォルダ名を変えてみたら、FFBが復活しました。
ってことは、きっと自分のマシンの個人設定のどこかがおかしいのではないか?と。
設定ファイルをあさりまくって、行きつきました。

c:\Users\(ログイン名)\Documents\Assetto Corsa\cfgのフォルダ内にある、
user_ff.iniというファイルです。
開くと、中はcar modごとの設定がこんな感じでずらっと並んでします。

[abarth500]
VALUE=1.000
[tky_toyota_supra_dekztax]
VALUE=1.000
[tky_mazda_mx5_2016]
VALUE=1.000
[tky_toyota_supra_dekztax_drift]
VALUE=1.000
[srp_honda_s2000_legendary]
VALUE=1.000
・・・

FFBが効かない車(car mod)の部分を見ると、VALUE=0.000となっている可能性があります。
これだと、この車に対してFFBが無効になるようです。
その時は、これをVALUE=1.000に書き直して保存すると、ゲーム中でFFBが復活します!

なんかこの車だけFFBが効かない、なんでだ?!ってときは、これも一応確認してみてください。直るかもしれません。

PITを設置するときの注意点(PITの枠が表示されない。表示されても一瞬で消える)

という事象に今日遭遇したのですが、速攻忘れそうなので覚書に残しておきます。

ことの発端は、ターンパイクのtrack modのカスタマイズで、PITの位置(オブジェクト名がAC_PIT_で始まるやつですね)を変更して、ゲームでテストをしてみたときのことです。
ゲームがスタートして、車を少し動かすと、PITの場所を示す赤い枠が表示されると思います。こういうやつです。

なんですが、一瞬表示されたらすぐに消えてしまって、それ以降PITとして認識されないという事象に出会ったわけです。
で、さっそくXに投げかけてみたところ、surfaces.iniが怪しいというご指摘が。
(あ~るさんありがとうございます!)
いろいろテストした結果をまとめるとこんな感じです。

1)対象となるレイアウトのdataフォルダにあるsurfaces.iniに定義されているSURFACEのセクションの中に、IS_PITLANE=1が含まれるものが必要。
2)1が設定されているSURFACEセクションのKEYに設定されている文字列がそのPITがある道路のオブジェクト名に含まれている必要がある。

です。私の例で具体的に書きます。今回ガソリンスタンドにPITを設置しようとしました。
まず、1の条件のため、このレイアウトのdata/surfaces.iniに下記のセクションを追加しました。

[SURFACE_3]
KEY=PIT
FRICTION=0.97
DAMPING=0
WAV=
WAV_PITCH=0
FF_EFFECT=NULL
DIRT_ADDITIVE=0
IS_VALID_TRACK=1
BLACK_FLAG_TIME=0
SIN_HEIGHT=0
SIN_LENGTH=0
IS_PITLANE=1
VIBRATION_GAIN=0
VIBRATION_LENGTH=0

IS_PITLANE=1がありますよね?でこのセクションに設定されたKEYは「PIT」です。
で、次にガソリンスタンドの床のオブジェクトの名前を、
1PIT_TURNPIKE_DAY_NML_・・・(長いので以下略)
という名前にしました。冒頭に1PIT_とつけています。
このPITという文字が入っているこの床オブジェクトはPITLANE扱いになるってことですね。
このオブジェクト(床・道路)の上にあるPIT設定(AC_PIT_)はPITの場所と認知されて、表示できるようになるということですね。
最初は普通の道路(ROAD)の上にAC_PIT_を設定したから、PITとして認識されず一瞬で消えてしまっていたのだと思います。

これで、ちゃんと車を移動しても、PITの表示が消えず、この枠に車を止めればピット作業ができるようになりました。

更に注意点が一つあります。)
surfaces.iniに設定されている各種SURFACEセクションにはそれぞれKEYが設定されています。
一方、オブジェクト名にこれらの中の複数の文字列が含まれる場合、(多分ですが)surfaces.iniで上に設定されたものから優先的にアサインされるようです。
例えば、道のROADと草のGRASSの順番で2つのKEYが存在したとして、オブジェクト名にROADとGRASSの両方が含まれている(順不同)と、そのオブジェクトはROADとして機能します。
今回、ROAD、PITの順でKEYを設定し、スタンドの床オブジェクトにROADとPITの両方の文字を含めたら、PITLANEとして認識できませんでした。
KEYの文字列が一つのオブジェクト内で複数含まれないように注意しましょう。

もう一つはおまけ情報。末梢神経さんに教えていただきました。ありがとうございます~!
通常ピットの作業はゲーム開始直後の設定画面で、PITの作業パターンを3種類設定できて、実際ピットに入ると、その中からどれかを自動で行われると思います。
ですが、下記のチェックをつけると、

PITに入った時、入れるガソリンや交換するタイヤを自分で指定するUIが表示されます。

レースなどタイム重視の時は自動の方が良いですが、スタンドで給油、みたいなシチュエーションであれば、手動の方が雰囲気出るかなと思います。

今回は以上です~!

木のオブジェクトの作り方

ターンパイクに2Dの木を植える作業をやりましたが、その覚書です。

trackに設置されている、木の作成にはちょっとしたコツがあるようです。
普通に木を植えて、ksEditor上でマテリアルにksTreeを設定してkn5を作るとこうなります。

これをこういう感じの木にするための方法です。

最終的にパーティクルの機能を使って木を大量に増やすわけですが、そのもとになる木のオブジェクトを少し加工します。
まず木の画が張り付いたオブジェクトを用意します。

編集モードに切り替え、オブジェクトの原点(オレンジの点)がオブジェクトの一番下に接するようにオブジェクトを上にずらします。

そしてこのオブジェクトを縦に細分化します。今回は2等分しました。
(縦に黄色い線が入っていますが、これは分割してません。映りこんでしまっただけです。)

この細分化はどれくらいやればよいのか明確にわかりませんが、後程マテリアルでksTreeの設定をした際、木としての表現がより細かくなるようです。

木の画が張り付いた1枚板のオブジェクトを複製し90度回転させて結合することで、十字の木が出来ます。

水色の線が法線。2方向だけに向いています。

さらにそれを複製して、法線の向きを逆にして、結合すると360度どこから見ても見える木が出来ます。

水色の法線が4方向を向いています。

こうして作られた木のオブジェクトを山ののり面に大量に生成します。
やりかたはこちら。
modelinghappy.com

生成した木は、オブジェクトに変換できます。
モディファイアプロパティを選択し、パーティクルシステムの枠内にある「インスタンスを実体化」をポチると、木一つ一つがオブジェクトに変換されていきます。
大量(10万個とか)でこれをポチると、blenderは当分応答しなくなると思いますので、ご注意ください。

個別に木が出来上がりますが、これを結合してはいけません。
木は一本ずつ別のオブジェクトにするべし、と書かれていました。(結合できれば、PCの負荷が下げられるんですが、ここは我慢)

続いて、木のオブジェクトの名前を変えます。木のオブジェクトには命名規則があり、

KSTREE_GROUP_

という文字で始まる名前が必要です。このまま、KSTREE_GROUP_1, KSTREE_GROUP_2,とつけても良いですし、
KSTREE_GROUP_OAK1_1, KSTREE_GROUP_OAK1_2,のように名前を追加して連番にするのも可能です。
今回は超大量に木を作っているため、一つずつ名前を変更していく作業は不可能です。
blenderで一気に名前変換を行います。
たとえば、今回の例ですと、ある木のグループはOak1.001, Oak1.002...となっていますので、
blenderの編集メニューから「名前を一括変更」を選択し、対象はすべて(オブジェクト)、検索がOak. 、変換がKSTREE_GROUP_OAK1_ として、OKを押します。
するとOak1で始まるオブジェクト名がすべてKSTREE_GROUP_OAK1_で始まるオブジェクト名に変わります。
他にも木の種類がある場合は、同様に名前を一括変換します。

これ、blender上では木1本ずつ、別々のオブジェクトになっているのですが、この命名規則に基づいてオブジェクト名を設定すると、ksEditorで読み込んだ時、同じグループ名のものは一つのオブジェクト(シェダー)にまとめられるようです。10万本をそのままゲームで読み込んだらカクカクで全く動かなくなってしまいますが、ksEditorがグループごとにまとめてくれることで、ゲームにも負荷がかからずに済みます。

できたらFBXでエクスポートして、ksEditorで読み込みます。
マテリアルでFBX_MATERIALが出てきて困る~というときは、一つ前の記事をご覧ください。

木のマテリアルにksTreeを設定し、パラメータを設定します。(この辺はお好みで)
最後に、kn5(track)を作成します。
これで完成です。

情報元はこちらです。
SHADER - setting-up trees | Assetto Corsa Mods

/* -----codeの行番号----- */