VRChatワールドで太陽を作り日の出~昼夜切り替えを時間経過で行う方法メモ

VRChatワールド 太陽 日の出 昼夜切り替え 時間経過 VRChat
※記事内に広告が含まれています。

バーチャル3Dクリエイター神部まゆみです(*^_^*)

この記事はVRChatワールドで太陽を作り昼夜切り替えを時間経過で行う方法についての記事です。

動作確認した最新バージョンは Unity 2022.3.22、VRChat SDK 3.10.1 です。

●PRスペース●
■PR■

現在、Unityアセットストアで毎日日替わりでアセットが無料配布されています。

A Free Asset Every Day | Unity Assets Store

ページに記載されているクーポンコードを決済画面で入力すれば0円になりますが、記載の日程は時差で日本より1日遅れてるっぽいので注意(つまり2026/01/01まで)。

〇まゆみマート|BOOTH

BOOTHでVRoidテクスチャやVRChat向けオブジェクトなどを販売しています。いいねしてくれると励みになります(*^-^*)

やりたいこと:VRChatワールドで時間経過で日の出~日没を実装し、昼夜切り替えしたい

私はゲーム制作もしていてUnityでやる方法は既に実装したので、これをUdon用に書き換えればすぐできそうな気がする。

ChatGPTパイセンに聞いてみる

Udonに書き換えるくらいなら彼に聞けば一発で終わるに違いない…。

VRChat 太陽 日の出 昼夜切り替え 時間経過
神部まゆみ
神部まゆみ

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

ChatGPT
ChatGPT

いいですね、その構成かなり“王道で正しい”です 👍
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版との違い

  • MonoBehaviourUdonSharpBehaviour
  • using 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の設定をします。

VRChatワールド 太陽 日の出 昼夜切り替え 時間経過

SunLight ディレクショナルライトを設定。普通はデフォルトでシーンにある。

MoonLight 夜用の薄暗いディレクショナルライト。新たに作る。

ゲーム時間 GameTimeを指定。

新たに作るのはMoonLightだけで、SunLightとゲーム時間のところは既にあるディレクショナルライトとUdonコンポーネントを指定するだけ。

夜用の薄暗いディレクショナルライトを作ってMoonLightに設定

夜用の薄暗いディレクショナルライトを作ってMoonLightに設定します。

色は #AFCBFF くらいの薄い青で、影なしにする。

これで設定が全部終わりました。

VRChatワールド 太陽 日の出 昼夜切り替え 時間経過

これで動いた!

おっこれで動きました!

C#をUdon#に書き換えるだけなら比較的ラクなのかな。

ゲーム内時間を他の人と同期したい場合、GameTimeを書き換える

このままだと後からインスタンスに入ってきた人と時間の同期ができないため、ちょっと書き換える必要があるっぽい。

VRChatワールド 太陽 日の出 昼夜切り替え 時間経過

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;
        }
    }
}

これならインスタンスオーナーが抜けても他の人に引き継がれるから大丈夫らしい。

VRChatワールド 太陽 日の出 昼夜切り替え 時間経過

時間を全くズレさせたくない場合はサーバーから時間を取得する方法があるらしいけど、処理がもう少し複雑になるみたいだからこれで十分らしいです。

おわりに

案外簡単に実装できて良かった。

あとはスカイボックス切り替えとか色々やってみたいけど、まぁ気が向いたらやってみるかもしれません。

また何かあれば追記します(*^_^*)

タイトルとURLをコピーしました