3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

p5.jsで詰まったこと 【シーンの切り替え方がわからない】

Last updated at Posted at 2020-07-11

#はじめに
初めまして!Life is Tech!メディアアートメンターのきゃみです!
今回p5.jsで作品を作らなければいけない案件ができたのですが、何個か詰まった点があったのでQiitaにまとめてみました。
今回はシーン切り替え編です!

#背景
p5.jsを使ってVJ映像を作りたいと思いたつも、二次元的な映像と三次元的な映像のシーンの切り替え方がわからず悩んでいたので、記事にまとめてみました。

#考えられるシーンの切り替え手法一覧
僕が実装を考える中で、シーンを切り替える方法が何点か思いついたので、まずはそれについて書いていこうと思います。
特に用途によって有効な手法が違うと思いますので、メリット・デメリットも書いていこうと思います。

###p5のライブララリを使う方法
p5にはSceneManagerというライブラリが公式に存在します。
本日の本題とはずれるので、詳しい書き方とかはReadmeなどをみていただければと思います。
個人的な印象ですが、二次元と三次元が入り混じっている場合この手法は適切ではないです。二次元の座標系が、WEBGL空間だとズレが生じるからです。特に、カメラが動いてしまう場合はもうどうしようもないです。(テクスチャを使ってゴニョゴニョすればいけないことはないのでしょうが、僕は実装できませんでした。)
今回の僕の作品ではShaderを多用していて、かつシーンの数も二個しかなかったのでこれは不採用としました。

###二つのテクスチャを交互に表示する方法

doubleTexture.js
let firstTexture;
let secondTexture;

function setup() {
    background(0);
    createCanvas(500, 500);
    firstTexture = createGraphics(500, 500);
    secondTexture = createGraphics(500, 500, WEBGL);
}

function draw() {
    // firstTextureに一つ目のシーンをレンダリング

    // secondTextureに二つ目のシーンをレンダリング

    if (frameCount % 1000 < 500) {
        image(firstSfirstTexturecene, 0, 0);
    } else {
        image(secondTexture, 0, 0);
    }
}

などとしてあげると、二つの異なる座標系の画面を交互に切り替えることでシーン切り替えが実現します。
しかし、最初の方法で書いたように、今回はShaderを適用させます。
特に、二つのシーンには同じShaderを適用させたいので、この方法ではコードを冗長化させてしまいます。
というわけでこちらも却下です。今回は、三つ目の方法を採用することにしました。

###一つのテクスチャに対して、書き込む内容を変える
一つだけテクスチャを用意し、条件によって書き込む内容を変えることでシーン切り替えを実現できます。
これはこれでかなりコードは冗長化してしまいますが、複数のシーンに同じShaderを適用させたい人はこれが最適になるのかなと思います。
カメラが動く場合も、二次元と三次元のシーンが入り混じる場合も、次のようにすれば実現可能となります。

singleTexture.js
let twoDTexture;
let mainTexture;

function setup() {
    background(0);
    createCanvas(500, 500);
    twoDTexture = createGraphics(500, 500);
    mainTexture = createGraphics(500, 500, WEBGL);
}

function draw() {
    //先にここで二次元のシーンをtwoDTextureにレンダリングしておく

    if (frameCount % 1000 < 500) {
        mainTexture.clear();
        mainTexture.camera(hoge, fuga, hogefuga, 0, 0, 0, 0, 1, 0);
        // mainTextureに三次元のレンダリング
    } else {
        mainTexture.clear();
        mainTexture.camera(0, 0, hogehoge, 0, 0, 0, 0, 1, 0);
        // mainTextureに2次元のレンダリング
        mainTextrue.texture(twoDTexture);
        mainTexture.plane(300);
    }

    // mainTextureを描画
    image(mainTexture, 0, 0);
}

ここから、このコードによって懸念点だった部分がどのように解消されているのかを書いていこうと思います。

##二次元と三次元をどのように両立させるか
今回においては、三次元のシーンは通常通りレンダリングし、二次元のシーンはplaneのテクスチャとして描画することにしました。
これにより、shaderを適用させる場合においても、同じテクスチャ内で実装できます。
普通、二次元と三次元では座標系が異なるので、カメラを動かす場合には描画においてズレが生じてしまいますが、シーンごとに別々のカメラ座標を持っておくことによってズレを防いでいます。
plane全体を映すのは、その時のテクスチャのサイズなどで変わると思いますので、環境ごとに自分で試行錯誤しながら設定してもらえればいいかなと思います。

しかし、これでももう一つの問題が生じてしまいます。
やっていただくとわかると思うのですが、シーンを切り替えているはずなのに一つ前のシーンが残ってしまうのです。
これについては、次のやり方で解消しています。

##clear()メソッドを使う
これは、テクスチャに現在描画されている色情報を、全て無に初期化するという機能です。
一見して何の役に立つかわからないこの関数ですが、今回のような場合には効果覿面です。
さっきの方法では、前のシーンのレンダリングが残ってしまっていました。
ゆえに、各シーンのレンダリング直前の部分に、clear()メソッドを入れ込むことによって、直前のシーンを残さずに切り替えを行うことができます。

#最後に
僕が今回作った作品はこちらになります。
Shaderの内容や、その設定方法についてはまた別の記事でまとめようと思いますので、気になる方はそちらも参照してみてください。
最後まで読んでいただき、ありがとうございました!

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?