xxxxxxxxxx
// TransformFeedbackのテスト。
// https://wgld.org/d/webgl2/w014.html
// 必要な準備はそろったので
// あとはshader用意してよろしく実行するだけ
// のはず...
// swapAttributeは必要なら用意する
// 要は紐付けに使うキーの名前をいじるだけなので。
/* procedure
書き込みに使うshaderを用意する
ここで読み出しの変数名と同じoutVaryingsっていうのを用意して
registPainterの第4引数に指定するのね
んでregistFigureの際に
書き込みに使うattrに対してoutIndex(outVaryingsにおけるindex)を
指定したうえでusageをdynamic_copyに指定する
普通にregistFigureする
んで描画の際にいつものuseの際に
書き込みで実行するドローコールの内容を事前通知する
あとは普通にunbindまで描画を実行
それが終わったら
書き込まれたattributeを使ってなんかする
なお
書き込みの際にラスタライズを実行しないことで
描画速度が向上する場合があります
*/
/*
TF失敗ですね。何がまずかったんだろ。
なるほど。bindBufferBase実行されてないわ。
attributeとして認識されないから取得できないんだ。困ったね。
vsのoutを取得できるように書き換えるか。
おめでとう🎉
attributeのswapにも成功していますね。
さっき作例漁ったらVAOでやってるのみっけた
VAOでもできるのかー
柔軟性考えたら
まあ
ないわ
いいよ合わせなくて。この枠組みで行こう。
どうせ処理を隠蔽しちゃえばどっちにしろ変わんないのはもうわかったから
あとはインターリーブ気になるわね(知識として)
*/
/*
個人的には砂のやつ、あれがどのくらい速くなるのかが気になるところ。boidsとか。
課題1: ラスタライズする場合のTFで描画と同時に更新
課題2: インスタンシングでオフセットだけTFでノンラスタライズで更新しつつそのデータとインスタンシングで大量描画
これによりboidsとかで...3次元のboidsとかで、立体のデータを一つだけ用意してその動かし方をboidsにする、
といったことが可能になるはず。やってみよう。
*/
/*
2024-11-13
やっぱこれおかしいわ
通常描画にswapが必要なわけないだろ
ちゃんと入れ替えられてないんだよな
...???
1回目の描画の後でaPositionは左下、aReadPositionは右上
ああ
だからひっくり返してるんか
そうなると
aPositionが右上になる
だからまたそれをずらして
...
このコードの場合は合ってるのか。まあいいや。
部分的に変えられないのは....
今の枠組みでは失敗するみたい。
*/
const ex = p5wgex;
let _node;
// データ書き込み用
// ラスタライズしない場合gl_Positionはどうでもいい。弾くことができる。
// h_doxasの作例でgl_PositionをoutVaryingsに指定してたけど
// 邪道でしょう
// 不採用にさせていただきました
const vsTransformOut =
`#version 300 es
in vec2 aPosition;
in vec4 aColor;
out vec2 aReadPosition;
out vec4 aReadColor;
void main(){
aReadPosition = aPosition - vec2(0.5);
aReadColor = aColor;
}
`;
// ラスタライズしない場合のfsはここまで簡単になる
// なんとprecisionすら必要としない。ただなくすことはさすがにできない。
// もちろんvoid main(){}も省いてはいけない。
const fsTransformOut =
`#version 300 es
void main(){}
`;
// データ出力用
const vsFeedbackIn =
`#version 300 es
in vec2 aPosition;
in vec4 aColor;
out vec4 vColor;
void main(){
vColor = aColor;
gl_Position = vec4(aPosition, 0.0, 1.0);
}
`;
const fsFeedbackIn =
`#version 300 es
precision highp float;
in vec4 vColor;
out vec4 fragColor;
void main(){
fragColor = vColor;
}
`;
function setup() {
createCanvas(600, 600, WEBGL);
pixelDensity(1);
_node = new ex.RenderNode(this._renderer.GL);
// まずTF用shaderを作る。
// いつものregistPainterにoutVaryingsの配列を加えて指定する。
_node.registPainter("transform", vsTransformOut, fsTransformOut, ["aReadPosition", "aReadColor"]);
_node.registPainter("feedback", vsFeedbackIn, fsFeedbackIn);
// 次にFigure,これもいつものregistFigureであるが、
// aReadPositionとaReadColorに関してはdynamicCopyを指定する。
// またさっきの配列(outVaryings)におけるインデックスをoutIndexの形で0,1,2,...で
// 指定する。これはデフォルトは-1である。0以上の場合にいろいろする。
_node.registFigure("TF", [
{name:"aPosition", size:2, data:[0,0,1,0,0,1]},
{name:"aColor", size:4, data:[1,0,0,1,0,1,0,1,0,0,1,1]},
{name:"aReadPosition", size:2, data:[0,0,1,0,0,1], usage:"dynamic_copy", outIndex:0},
{name:"aReadColor", size:4, data:[1,1,1,1,1,1,1,1,1,1,1,1], usage:"dynamic_copy", outIndex:1}
]);
// おわりです。
_node.clearColor(0.5, 0.7, 0.8, 1);
}
function draw() {
_node.clear();
// まずデータの受け渡し。
// データを渡した後でswapAttributeを実行して
// shaderのaPositionとaColorでaReadPositionとaReadColorが参照されるようにする
// "points"とありますがここはラスタライズしない場合どうでもいいです
// どうでもよくないのはラスタライズと同時に更新する場合ですね
// 更新だけの場合はラスタライズしないのでドローコールは何でもいいし
// gl_Positionも完全にどうでもいいですね
// pointsをlinesにするとおかしくなるのはおそらく3つ目が無視されるからですね
// trianglesなら全部使われるので問題ないです
// あんまおかしなことしない方がいいです。pointsなら問題なくすべてのattrが
// 呼ばれるのでその方が無難です(あくまでラスタライズしない場合)
// またtriangle_stripでもエラーをおこします(処理が実行されない)
// 実はpoints,lines,triangles以外はエラーになるようです
// https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext/beginTransformFeedback
// 注意しましょう。
_node.use("transform", "TF", "points");
_node.enable("rasterizer_discard")
.drawArrays("points")
.disable("rasterizer_discard")
.swapAttribute("aPosition", "aReadPosition").swapAttribute("aColor", "aReadColor")
.unbind();
// aReadPositionとaReadColorをaPosition,aColorの形で使用して描画する
// 描画が終わったらswapしたattributeを元に戻す
_node.use("feedback", "TF")
.drawArrays("triangles")
.swapAttribute("aPosition", "aReadPosition").swapAttribute("aColor", "aReadColor")
.unbind();
_node.flush();
}