WebGL-Native: WebGLの実装
prev: https://zenn.dev/okuoku/scraps/99fa92f6aae12e
next: https://zenn.dev/okuoku/scraps/7bf87a81129b7d
WebGLの実装
前回までで、Node.jsからOpenGL ES2を呼び出す環境を作ることができた。ということは、後はひたすらWebGLのメソッドを埋めていけばWebGL実装のできあがりということになる。(ステートの読み出しは対応してないけど)
... というわけで、全14章あるものを無心に実装していく。。
5.14.1 Attributes
drawingBufferWidth
と drawingBufferHeight
は、とりあえず初期化時のサイズをそのまま返却することにした。
canvas
は一旦ユーザ側で埋めてもらうって事で。。初期化APIを替えちゃった方が良いな ★ 。
5.14.2 Getting information about the context
Emscriptenは使ってないのでとりあえず何も返却しないstubにした。
5.14.3 Setting and getting state
getParameterが4要素受けとるのに4バッファをallocしてるのは非効率なのでC APIを見直したいかな。。 ★
5.14.4 Viewing and clipping
最初UnityがべらんめぇなScissor (0,0)-(1,1)
を設定してきて何かと思ったらCanvasの clientWidth
clientHeight
を見ている所為だった。。とりあえず適当に埋めればOK。
5.14.5 Buffer objects
最初 length
と byteLength
をとり違えてた。。JavaScriptの length
は要素数なので、 Uint32Array
等が来る可能性を考えると常に byteLength
を使うのが正しい。
↓ のようなテストで、常に 32
バイトしかバッファされなくて発覚した。
let buf = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buf);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, 32, gl.STATIC_DRAW);
console.log(gl.getBufferParameter(gl.ELEMENT_ARRAY_BUFFER, gl.BUFFER_SIZE)); // ★ → 32
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint32Array(32), gl.STATIC_DRAW);
console.log(gl.getBufferParameter(gl.ELEMENT_ARRAY_BUFFER, gl.BUFFER_SIZE)); // ★ → 128
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
gl.deleteBuffer(buf); // ★ 本来不要
あと、WebGLの仕様では、 deleteBuffer
は明示的にやらなくても良いので、GCとの統合を実装しておく必要がある。C言語側でやるか。JS側でやるか悩み中。
5.14.6 Framebuffer objects
void deleteFramebuffer(WebGLFramebuffer? buffer)
If
framebuffer
was generated by a differentWebGLRenderingContext
than this one,
仕様書のtypoかな(仮引数が buffer
→ framebuffer
)。
↓に書いた通り、UnityがWebGLの DEPTH_STENCIL
renderbufferを活用しているため、暗黙にステンシルバッファを生成してバインドするコードを追加している。
5.14.7 Renderbuffer objects
これも DEPTH_STENCIL
の専用対応。こういうのはJS側でやった方が良い気がしているが、そもそも何でWebGLとOpenGLで差があるのかを調べた方が良さそう ★ 。どうせDirectXの仕様じゃないかなという気はするけど。
5.14.8 Texture objects
★ 圧縮テクスチャは未実装。まぁQA面倒だし。。
5.14.9 Programs and Shaders
5.14.10 Uniforms and attributes
最後の大物。。
EmscriptenはUniformのリストを事前に展開して整数idにマップするようになっているので、 getActiveUniform
の実装が必須だった。というわけで追加している。
あと、仕様( https://www.khronos.org/registry/OpenGL-Refpages/es2.0/xhtml/glUniform.xml )の"number of elements"の意味をとり違えていて、要素数をそのまま渡していた。ベクタの長さで割るのが正解。
5.14.11 Writing to the drawing buffer
5.14.12 Reading back pixels
絵が出た
ここまででやっと絵が出た。。
- 実行完了: https://github.com/okuoku/cwgl-proto/commit/875bb8d03f4cbe678a168f1da1b227e6d6a72a16
- 絵出し: https://github.com/okuoku/cwgl-proto/commit/b4eeec13138538bd80af29dc0bf0994b44dd496c
結局クエリ系は必要だったので必要なものだけ実装。。
6.8 Framebuffer Object Attachments
UnityがDepthを取るのにこっちを使っているっぽいな。。
出画した
長く苦しい戦いだった。。