Frame of 42yeah

Site Defunct

注意!截止到 16/9/2019 ,这个博客已经被搬迁到了 这里 。以后我的东西都会发在那里。拜拜啦!

WebAssembly 中的 OpenGL(ES?)

注意,看这个可能需要有一定的 OpenGL/WebGL 基础。

OpenGL 是一个计算机图形学的库。更确切的说(防刚),是一套 specification 。通过 OpenGL 给的各种接口你可以绘制出各种炫酷玩意儿。对这个有兴趣的可以来 这里 学一下。强烈推荐!!

WebAssembly 可以和 Javascript 互相通讯,进而调整 DOM 中的内容。所以,很明显,用 C/C++ 写 OpenGL/ES 代码,然后把内容显示在网页上,再也不是不可能了!!!

马上开始!!

我们现在要用多一个头文件了。除了 emscripten.h 之外,我们还要 #include 多一个 emscripten/html5.h ,这样我们才有 WebGL 的各种接口。废话少说,我们可以马上看一下我们的 include 模版:

#include <emscripten.h>
#include <GLES3/gl2.h>
#include <EGL/egl.h>
#include <emscripten/html5.h>

有了这一堆头文件,我们至少可以画出一个三角形了。所以我们的下一步是。。。

创建上下文!!

如果有一点 OpenGL 家族的基础的话,就会知道 在创建 context 之前,画什么都是没用的。 因此,我们要先创建一个 Context ,接下来才能愉快的玩耍。

int main(void) {
  EmscriptenWebGLContextAttributes attrs;
  attrs.explicitSwapControl = 0;
  attrs.depth = 1;
  attrs.stencil = 1;
  attrs.antialias = 1;
  attrs.majorVersion = 2;
  attrs.minorVersion = 0;

  EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context = emscripten_webgl_create_context(0, &attrs);

  return 0;
}

我不喜欢 emscripten 的命名的一个地方就是名字都长的跟串儿似的。看看别人 OpenGL 命名的多好,都是 gl啥啥啥 的。

跑题了。咱可以看得见,首先我们搞了个 attrs ,然后给里面的一堆东西赋了个值。看起来贼多对不?没事,我们一个个看(里面有一部分可能你已经知道是什么了):

接下来我们往下看,就看到创建 context 的步骤了:

EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context = emscripten_webgl_create_context(0, &attrs);

我们可以看到,命名仍然是长的一批。但是没关系,这里大概可以看得懂了吧:我们通过 emscripten_webgl_create_context 创建了一个上下文。

在这个创建上下文的函数里面,有两个参数。第一个参数我用了 0 ,但其实这里可以填任意 canvas 的 ID; 如果为 0 ,就会用在 Javascript 里面 预先由你 定义好的变量:Module.canvas 。创建完毕之后的 context ,其实就是个 int ,只是被 typedef 了一下而已。他应该返回一个正数,如果返回的是 0 ,那就是意味着创建失败了;如果返回的是负数,那你就可以通过把它当成 EMSCRIPTEN_RESULT 然后 switch 这堆东西来看看是什么地方出错了。

当然咯,创建好之后还要把这个 context 设置成当前的 context 。我们只需要这样:

emscripten_webgl_make_context_current(context);

就可以了。

测试!

要测试你是不是成功了非常简单,清一下屏幕就可以了:

glClearColor(0.3f, 0.2f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

然后。。。我发现我好像一直都忘了说编译!!

编译!

编译带 GL 的规则跟平时的略有不同,我直接上命令了,方便大家:

emcc main.c -o main.js -s WASM=1 -s EXTRA_EXPORTED_RUNTIME_METHODS="[ 'ccall', 'cwrap' ]" -s FULL_ES2=1 -s USE_WEBGL2=1

之前的那一堆都差不多是一样的;我加上 EXTRA_EXPORTED_RUNTIME_METHODS 只是为了防止不时之需,不一定需要。但看看后面那两句:

-s FULL_ES2=1 -s USE_WEBGL2=1

这两句才是这编译能过的主要原因。我们可以看得出我们这里在用 GLES2/WebGL2 。然后按下回车,他大!我们编译好啦!

回到测试!

在浏览器里打开,我们应该能够看见一个屎黄色的矩形:

屎黄色

成功!!!!

这就证明我们成功了!!为了再吸引一下你们的兴趣,给你看看我之后写好的三角形(来到这,诸位学过的应该都已经会了吧):

对了,说多一句,因为有点怕这个三角形会卡爆你的浏览器(真的会吗???),所以我弄了个按钮,点了才会开始主循环哦:

对了,再说多一句,点了之后 Javascript 控制台可能会抛出个异常,没事,他只是在模拟真正的主循环而已:

开始!

评论区