0

このビデオを見た後、私は現在のプロジェクトでそのようなものをどのように実装できるかを考え始めました。コードの大部分をリアルタイムで編集可能にするのは難しいと思いますが、ゲームをプレイするときに、少なくともOpenGLシェーダーを編集可能にできると思いました。

FileSystemWatcherだから私は:を設定しました

protected void WatchShaders()
{
    _uiDispatcher = Dispatcher.CurrentDispatcher;
    const string shaderDir = @"path\to\my\shaders";
    _shaderFileWatcher = new FileSystemWatcher(shaderDir);
    _shaderFileWatcher.NotifyFilter = NotifyFilters.LastWrite;
    //fw.Filter = "*.frag;*.vert";
    _shaderFileWatcher.Changed += ShaderChanged;
    _shaderFileWatcher.EnableRaisingEvents = true;
}

そして今、ファイルが変更されるたびにシェーダーを更新したいと思います。

void ShaderChanged(object sender, FileSystemEventArgs e)
{
    _shaderFileWatcher.EnableRaisingEvents = false; // prevent more/duplicate events from firing before we've finished processing the current one

    lock (_bfShader)
    {
        _bfShader.AttachShader(Shader.FromFile(e.FullPath));
        _bfShader.Link();
        _bfShader.Use();

        _bfProjUniform = new Uniform(_bfShader, "ProjectionMatrix");
        _bfSampler = new Uniform(_bfShader, "TexSampler");
        _bfSampler.Set1(0);
    }
    _shaderFileWatcher.EnableRaisingEvents = true;
}

問題は、シェーダーファイルを編集するとすぐに、次のような例外がスローされることです。

呼び出し元のスレッドに現在のコンテキストはありません

そこで、掘り下げてみると、OpenGLコンテキストは基本的に単一のスレッドにバインドされていることがわかりました。AFAIK、これには2つの回避策があります。

  1. メインUIスレッドでOpenGLコンテキストを無効にし、他のスレッドで有効にして、自分の作業を行ってからリセットします
  2. イベントをメインUIスレッドにディスパッチします

メインスレッドはOpenGL呼び出しでいっぱいなので、(1)をどのように実装するかわかりません...どこで有効または無効にするかわかりません。

したがって、ファイル変更イベントをメインスレッドにディスパッチする方法がわからないことを除いて、オプション(2)が残ります。

この記事は言う:

GLControlは、GLControl.BeginInvoke()メソッドを提供して、セカンダリスレッドからメインのSystem.Windows.Forms.Applicationスレッドへの非同期メソッド呼び出しを簡素化します。GameWindowは同様のAPIを提供していません。

残念ながら、私はを使用しているGameWindowので、その機能にアクセスする方法がわかりません。

では、イベントをメインUIスレッドにディスパッチする最も簡単な方法は何ですか?OpenTKライブラリまたは別のできればWindows専用ではないライブラリを使用していますか?

4

1 に答える 1

3

キューを使用して、それを取り除くことができると考えました。

void ShaderChanged(object sender, FileSystemEventArgs e)
{
    _shaderFileWatcher.EnableRaisingEvents = false; // prevent more/duplicate events from firing before we've finished processing the current one

    lock (_renderQueue)
    {
        _renderQueue.Enqueue(() =>
            {
                switch(e.Name)
                {
                    case "block.frag":
                        _bfShader.DetachShader(_blockFragShader);
                        _blockFragShader = Shader.FromFile(e.FullPath);
                        _bfShader.AttachShader(_blockFragShader);
                        break;
                    default:
                        return;
                }

                Trace.TraceInformation("Updating shader '{0}'", e.Name);

                _bfShader.Link();
                _bfShader.Use();

                _bfProjUniform = new Uniform(_bfShader, "ProjectionMatrix");
                _bfSampler = new Uniform(_bfShader, "TexSampler");
                _bfSampler.Set1(0);
            });
    }

    _shaderFileWatcher.EnableRaisingEvents = true;
}

次に、レンダリングループを少し変更します。

lock(_renderQueue)
{
    while(_renderQueue.Count > 0)
    {
        _renderQueue.Dequeue().Invoke();
    }
}
于 2012-03-03T20:21:28.347 に答える