1

3D モデリング アプリケーション用のプラグインを開発しています。このアプリケーションには、自動化したいサードパーティのプラグイン (レンダリング エンジン) もあります。

私がしているのは、 Camera のリストを作成しList<Camera> cameraViews、それらすべてを繰り返し処理し、レンダリングエンジンにレンダリングを開始するように指示することです

foreach ( Camera camera in cameraViews )
{
    // tell the modellingApplication to apply camera
    modellingApplication.ApplyCameraToView(camera);

    // tell the render engine to render the image
    string path = "somePathWhereIWantToSaveTheImage"
    renderEngine.renderCurrentScene(path)

    // .renderCurrentScene() seems to be async, because my code, which is on the UI thread
    // continues... so:

    // make sure that the image is saved before continuing to the next image
    while ( !File.Exists(path) )
    {
        Thread.Sleep(500);
    }
}

ただし、これは機能しません。renderplugin は非同期処理を行っているように見えますが、この非同期処理を行うとき、情報を取得するためにメイン スレッドを呼び出しています。

これに対する回避策を見つけました。レンダリング エンジンを呼び出してレンダリングした直後に、MessageBox を呼び出します。これにより、コードの続行がブロックされますが、非同期呼び出しは引き続き処理されます。私は知っています、これは奇妙な振る舞いです。さらに奇妙なのは、renderengine が情報を得るために UI スレッドの呼び出しを完了し、独自のプロセスを続行すると、MessageBox が自動的に閉じられるという事実です。イメージがディスクに保存されているかどうかを確認するために、コードを while ループに継続させます。

foreach ( Camera camera in cameraViews )
{
    // tell the modellingApplication to apply camera
    modellingApplication.ApplyCameraToView(camera);

    // tell the render engine to render the image
    string path = "somePathWhereIWantToSaveTheImage"
    renderEngine.renderCurrentScene(path)

    // .renderCurrentScene() seems to be async, because my code, which is on the UI thread
    // continues... so:

    // show the messagebox, as this will block the code but not the renderengine.. (?)
    MessageBox.Show("Currently processed: " + path);

    // hmm, messagebox gets automatically closed, that's great, but weird...

    // make sure that the image is saved before continuing to the next image
    while ( !File.Exists(path) )
    {
        Thread.Sleep(500);
    }
}

メッセージボックスの部分を除けば、これは素晴らしい。メッセージボックスを表示したくありません。スレッド全体をブロックせずにコードを一時停止したいだけです (renderengine から ui スレッドへの呼び出しは引き続き受け入れられるため)。

レンダリング エンジンが非同期で作業を行わなければ、はるかに簡単だったでしょう..

4

1 に答える 1

0

これが最良の答えだとは思いませんが、それがあなたが探しているものであることを願っています。これは、スレッドの続行をブロックする方法です。

    // Your UI thread should already have a Dispatcher object. If you do this elsewhere, then you will need your class to inherit DispatcherObject.
    private DispatcherFrame ThisFrame;

    public void Main()
    {
        // Pausing the Thread
        Pause();
    }

    public void Pause()
    {
        ThisFrame = new DispatcherFrame(true);
        Dispatcher.PushFrame(ThisFrame);
    }

    public void UnPause()
    {
        if (ThisFrame != null && ThisFrame.Continue)
        {
             ThisFrame.Continue = false;
             ThisFrame = null;
        }
    }

途中でブロックしながら、そのスレッドでアクションを受信して​​実行したい場合は、次のようにすることができます。これは、うーん...ちょっとハックな感じがするので、これを入力したときに重大な間違いを犯していないことを確認せずに、コピーして貼り付けないでください。私はまだコーヒーを飲んでいません。

// Used while a work item is processing. If you have something that you want to wait on this process. Or you could use event handlers or something.
private DispatcherFrame CompleteFrame;
// Controls blocking of the thread.
private DispatcherFrame TaskFrame;

// Set to true to stop the task manager.
private bool Close;

// A collection of tasks you want to queue up on this specific thread. 
private List<jTask> TaskCollection;

public void QueueTask(jTask newTask)
{
    //Task Queued.

    lock (TaskCollection) { TaskCollection.Add(newTask); }
    if (TaskFrame != null) { TaskFrame.Continue = false; }
}

// Call this method when you want to start the task manager and let it wait for a task.
private void FireTaskManager()
{
    do
    {
        if (TaskCollection != null)
        {
            if (TaskCollection.Count > 0 && TaskCollection[0] != null) 
            { 
                ProcessWorkItem(TaskCollection[0]);
                lock (TaskCollection) { TaskCollection.RemoveAt(0); }
            }
            else { WaitForTask(); }
        }
    }
    while (!Close);
}

// Call if you are waiting for something to complete.
private void WaitForTask()
{
    if (CompleteFrame != null) { CompleteFrame.Continue = false; }

    // Waiting For Task.

    TaskFrame = new DispatcherFrame(true);
    Dispatcher.PushFrame(TaskFrame);
    TaskFrame = null;
}

/// <summary>
/// Pumping block will release when all queued tasks are complete. 
/// </summary>
private void WaitForComplete()
{
    if (TaskCollection.Count > 0)
    {
        CompleteFrame = new DispatcherFrame(true);
        Dispatcher.PushFrame(CompleteFrame);
        CompleteFrame = null;
    }
}

private void ProcessWorkItem(jTask taskItem)
{
    if (taskItem != null) { object obj = taskItem.Go(); }
}
于 2013-08-06T14:55:20.327 に答える