バーチャル3Dクリエイター神部まゆみです(*^_^*)
この記事はVRChatワールドで太陽を作り昼夜切り替えを時間経過で行う方法についての記事です。
動作確認した最新バージョンは Unity 2022.3.22、VRChat SDK 3.10.1 です。
やりたいこと:VRChatワールドで時間経過で日の出~日没を実装し、昼夜切り替えしたい
私はゲーム制作もしていてUnityでやる方法は既に実装したので、これをUdon用に書き換えればすぐできそうな気がする。
ChatGPTパイセンに聞いてみる
Udonに書き換えるくらいなら彼に聞けば一発で終わるに違いない…。




VRChatでワールド作成をしています。ディレクショナルライトを太陽にして24時間の昼夜システムを作りたいです。 Unityでゲーム制作もしているのでそこで実装したスクリプトがあるのですが、これをUdonに書き換えて実装できないでしょうか?


いいですね、その構成かなり“王道で正しい”です 👍
Unityでちゃんと昼夜サイクルを組んでいる人がVRChatに来ると、ほぼ同じことをUdonSharpでそのまま再現できます。
結論から言うと 問題なく書き換え可能です。
全体方針(VRChat向け)
VRChatでは
- UdonSharp を使う(C#ほぼそのまま書ける)
- 通常は
- 時間管理用 Udon
- 太陽制御用 Udon
を分けてもOK(Unity時代の設計そのまま)
今回はあなたの構成をそのまま活かします。
① GameTime を UdonSharp に書き換え
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;
public class GameTime : UdonSharpBehaviour
{
[Header("Game Time")]
[Range(0f, 24f)]
public float currentTime = 6f; // 朝6時スタート
[Tooltip("1日が何秒か")]
public float dayLengthInSeconds = 240f;
void Update()
{
float timeSpeed = 24f / dayLengthInSeconds;
currentTime += Time.deltaTime * timeSpeed;
if (currentTime >= 24f)
{
currentTime -= 24f;
}
}
}
✅ Unity版との違い
MonoBehaviour→UdonSharpBehaviourusing VRC.*が増えただけ
② SunController を UdonSharp に書き換え
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;
public class SunController : UdonSharpBehaviour
{
[Header("References")]
public Light sunLight;
public Light moonLight;
public GameTime gameTime;
[Header("Intensity")]
public float sunMaxIntensity = 1.2f;
public float moonMaxIntensity = 0.3f;
[Header("Ambient")]
public float dayAmbient = 1.0f;
public float nightAmbient = 0.2f;
void Update()
{
if (gameTime == null) return;
float time01 = gameTime.currentTime / 24f;
// ===== 太陽の回転 =====
float sunAngle = time01 * 360f - 90f;
sunLight.transform.rotation = Quaternion.Euler(sunAngle, 170f, 0f);
// ===== 太陽の明るさ =====
float sunIntensity = Mathf.Clamp01(
Mathf.Cos((gameTime.currentTime - 12f) / 24f * Mathf.PI * 2f)
);
sunLight.intensity = sunIntensity * sunMaxIntensity;
// ===== 月の回転 =====
moonLight.transform.rotation =
Quaternion.Euler(sunAngle + 180f, 170f, 0f);
// ===== 月の明るさ =====
float moonIntensity = 1f - sunIntensity;
moonLight.intensity = moonIntensity * moonMaxIntensity;
// ===== 環境光 =====
RenderSettings.ambientIntensity =
Mathf.Lerp(nightAmbient, dayAmbient, sunIntensity);
}
}
これもほぼそのままですね。
③ Unity / VRChat 側の設定ポイント(重要)
ここがハマりやすいので要注意です。
🔹 ライト設定
- Sun / Moon 両方とも
- Type: Directional
- Mode: Realtime
- Shadow は重くなるので
- Sunのみ Shadow ON
- Moonは OFF 推奨
🔹 Lighting Settings
- Environment Lighting
- Source: Color
- Ambient Mode: Realtime
- Skybox を使う場合
→ Skyboxマテリアルも回転させると超リアルになります
🔹 UdonSharp
- 必ず
Compile All UdonSharp Programs - ワールドビルド前にエラーゼロを確認
④ VRChat向け改善アイデア(余談)
あなたのコード、VRChatでさらに映える改良案もあります。
🌅 朝焼け・夕焼け
Gradientを使って- 太陽の色
- Ambient Color
を時間で変える
🌍 プレイヤー同期
Networking.IsOwnerで- ワールドオーナーだけ時間を進める
- 他プレイヤーは同じ時刻を見る
⚡ パフォーマンス
Update()→LateUpdate()or
0.1秒ごと更新(Timer方式)
まとめ
- ✅ 今のUnityコードはそのままUdonSharpで使える
- ✅ 構造も設計もVRChat向き
- ✅ ディレクショナルライト太陽24時間サイクルは問題なし
かなり“わかってる人の設計”なので、ここまでできていれば
空の色・霧・星・雲まで行くと一気に神ワールドになります 🌌
なんか簡単にできそう?
既にC#のスクリプトがあるから書き換えるだけで済むので楽かな。
実際に実装してみる
ChatGPT氏はちょくちょく大ウソを言うこともあるので実際に動かしてみます。
空のオブジェクトを作成、Udon Behaviorを追加してスクリプトをコピペする
空のオブジェクトを作成、適当に名前を付けてUdonBehaviorを追加、Udon#で新しいプログラムを作りGameTimeって名前にしてスクリプトをコピペします。
GameTimeのコードはこれ。
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;
public class GameTime : UdonSharpBehaviour
{
[Header("Game Time")]
[Range(0f, 24f)]
public float currentTime = 6f; // 朝6時スタート
[Tooltip("1日が何秒か")]
public float dayLengthInSeconds = 240f;
void Update()
{
float timeSpeed = 24f / dayLengthInSeconds;
currentTime += Time.deltaTime * timeSpeed;
if (currentTime >= 24f)
{
currentTime -= 24f;
}
}
}
SunControllerも同様に作ってコピペします。
SunControllerの設定をする
GameTimeは時間の設定ができるけどとりあえずデフォルトで問題なし、SunControllerの設定をします。


SunLight ディレクショナルライトを設定。普通はデフォルトでシーンにある。
MoonLight 夜用の薄暗いディレクショナルライト。新たに作る。
ゲーム時間 GameTimeを指定。
新たに作るのはMoonLightだけで、SunLightとゲーム時間のところは既にあるディレクショナルライトとUdonコンポーネントを指定するだけ。
夜用の薄暗いディレクショナルライトを作ってMoonLightに設定
夜用の薄暗いディレクショナルライトを作ってMoonLightに設定します。
色は #AFCBFF くらいの薄い青で、影なしにする。
これで設定が全部終わりました。


これで動いた!
おっこれで動きました!
C#をUdon#に書き換えるだけなら比較的ラクなのかな。
ゲーム内時間を他の人と同期したい場合、GameTimeを書き換える
このままだと後からインスタンスに入ってきた人と時間の同期ができないため、ちょっと書き換える必要があるっぽい。


GameTimeを以下のように書き換えます。
ちゃんと動いたからたぶん大丈夫だと思う。
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;
public class GameTime : UdonSharpBehaviour
{
[UdonSynced]
public float currentTime = 6f;
public float dayLengthInSeconds = 240f;
private bool isTimeRunning = false;
void Start()
{
// 開始時、オーナーなら動かす
if (Networking.IsOwner(gameObject))
{
isTimeRunning = true;
}
}
void Update()
{
if (!isTimeRunning) return;
if (!Networking.IsOwner(gameObject)) return;
float timeSpeed = 24f / dayLengthInSeconds;
currentTime += Time.deltaTime * timeSpeed;
if (currentTime >= 24f)
{
currentTime -= 24f;
}
}
public override void OnOwnershipTransferred(VRCPlayerApi newOwner)
{
// 自分が新オーナーになった場合
if (Networking.IsOwner(gameObject))
{
isTimeRunning = true;
}
else
{
isTimeRunning = false;
}
}
}
これならインスタンスオーナーが抜けても他の人に引き継がれるから大丈夫らしい。


時間を全くズレさせたくない場合はサーバーから時間を取得する方法があるらしいけど、処理がもう少し複雑になるみたいだからこれで十分らしいです。
おわりに
案外簡単に実装できて良かった。
あとはスカイボックス切り替えとか色々やってみたいけど、まぁ気が向いたらやってみるかもしれません。
また何かあれば追記します(*^_^*)




