将15000行代码从C++编译为WebAssembly,是种怎样的体验?指针头文件

首先,交代一下背景。Webots是一个开源机器人模拟器。为了满足需求,Webots拥有自己的渲染引擎:Wren(WebotsRenderingEngine)。Wren是用C++编写的,而且依赖OpenGL3.3。但是,Wren的公共API是用C编写的,这一点很重要,稍后我们会介绍原因。

此外,Webots还支持将模拟的动画录制下来,或者进行直播。然后,你就可以在浏览器中查看生成的动画或直播了。之前,我们使用Three.js作为渲染引擎在Web上显示Webots模拟。Three.js的运行良好,但它与Wren有一些本质上的区别,因此很难在桌面和Web上获得相同质量的图形显示。

经过一次彻底的分析后,我们决定将Wren移植到WebAssembly。

通过下面的图片,你可以看出编译成WebAssembly后,Wren的图形质量有了巨大的飞跃。

左:桌面版;中:Three.js显示的Web版;右:编译成WebAssembly后的Web版

总体的规划

我将项目分成了两个主要部分:

最后,我还会介绍一些我遇到的主要问题,并提供一些常见的建议。

第一步:准备代码

为了能够使用WebAssembly编译代码,首先我需要做一系列的准备。主要工作包括以下三项:

依赖关系

在使用Emscripten导出代码时,依赖关系很快就会变成一场噩梦。然而,我很幸运,Wren只有三个依赖项:OpenGL、glad和glm。

由于上述原因,我几乎不需要担心依赖关系。但是,我仍然想提一下,因为我觉得如果你的代码有庞大的依赖关系,例如物理引擎,则依赖关系很可能会成为一个巨大的挑战。

修改头文件并排除有问题的函数

首先,我必须修改头文件,才能使用Emscripten。在这一步中,大部分的修改都是将glad的头文件换成纯OpenGL头文件。

#ifdef__EMSCRIPTEN__#include#include#else#include#endif

接下来,我排除了渲染引擎中的一些不兼容Web的函数。由于事先无法得知哪些函数不能用Emscripten编译,所以我只能反复试验。

最终,我发现必须排除的函数主要分为两大类:

准备导出函数和/或枚举

我必须在Makefile中设置一些正确的标志(主要是为了OpenGL),这样就可以编译渲染引擎了。然而,事情远非这么简单。

问题是,用这种方法编译之后,我无法通过JavaScript访问Wren的任何功能。其背后原因是,Emscripten在编译你提供的文件时,会将其作为可执行文件:一旦编译完成,启动该文件,就应该执行些什么。但是,这不是我想要的使用方式,我希望将其作为库来使用,我需要访问其中的各个函数。

幸运的是,这个问题有现成的解决方案。事实上,如果你使用C,则有一种解决方案;如果使用C++,则有两种解决方案。

C的解决方案更为简单,实现速度也更快。你只需在链接时指定所有希望能够在JavaScript中使用的函数的名称。请不要忘记,必须在函数名称的开头添加下划线。

接下来,我只需要将下列选项添加到链接中:

-sEXPORTED_FUNCTIONS=’[$(shellcatfunctions_to_export.txt)]’

然后,我就可以从JavaScript访问每个函数了。

至此,我成功编译了整个渲染引擎。结果得到了三个文件:

请注意,虽然我已经编译了渲染引擎,但不意味着没有任何问题。前路还很漫长……

第二步:修改代码

乏味的工作开始了。

Webots使用了Three.js,可在Web上运行,我的目标是使用WebAssembly编译Wren。问题在于:Three.js和Wren之间没有一对一的映射关系。所以,我们不得不从头开始。首先,我建立了一个非常简单的概念证明:一个白色的立方体。然后,我在其之上构建了其他几何图形、外观、光照、阴影……

但文本主要讨论的是WebAssembly部分。

我采用的方法如下:

下面,我们来谈一谈我所遇到的问题。

问题

我遇到的绝大多数问题可分为以下两类:

指针

Wren的C接口中使用了大量的指针:函数接收指针参数,并返回指针。

而另一方面,JavaScript中没有指针。为了在Web上使用Wren,我必须编写它与JavaScript的接口。

如果将C函数的返回值(一个指针)赋给一个JavaScript变量,会怎么样呢?JavaScript会将其当成一个简单的整数。其实这样正合适,因为如果将这个整数传递给另一个接受指针的C函数,就能顺利地运行。

如果将JavaScript数组或对象作为参数,发送给需要指针的C函数,就会出现问题。C函数会尽最大努力理解收到的数据,但大多数情况下都会失败。

例子

我在项目开始时遇到了如下案例:

我可以加载网页,而且没有任何错误和警告。

虽然背景颜色已设置,但无论JavaScript数组中的值是什么,背景始终为红色。

发生这种情况,是因为C函数在努力翻译我传递过去的数组,最终它认为整个JavaScript结构为红色值。

如果你打算在JavaScript中使用Emscripten编译函数,那么可以通过这个案例学到一个重要的教训:小心没有任何错误和警告的问题!对于我遇到的这种情况,很明显什么地方出问题了,但你有可能会遇到不同的问题,有的时候甚至会让你抓狂!

幸运的是,有一些解决方案可以将JavaScript对象传递给Emscripten。在这个项目中,我结合使用了以下三种方案:

1、使用Emscripten的方法ccall和cwrap。为此,必须添加以下编译选项:

-s‘EXPORTED_RUNTIME_METHODS=[“ccall”,“cwrap”]’

如下所示,我们可以使用ccall和cwrap调用一些C函数,但需要指定参数的类型。这种方法非常适合处理字符串,但如果需要传递数组,那么这些函数的用途就会很有限。

Module.ccall('wr_post_processing_effect_pass_set_name',null,['number','string'],[colorPassTrough,"colorPassThrough"]);

请注意this.previousInverseViewMatrixPointer,这是我们从另一个C函数获得的指针,我们将其定义为类型为number的指针。

2、对于数组,你可能需要使用Emscripten内置的malloc和free实现。这个方法稍微有点复杂:

varbuf=Module._malloc(myTypedArray.length*myTypedArray.BYTES_PER_ELEMENT);Module.HEAPU8.set(myTypedArray,buf);Module.ccall('my_function','number',['number'],[buf]);Module._free(buf);

这段代码会分配一个缓冲区,填充,然后传递给C函数,然后再释放。

3、使用一个C静态函数作为过渡。我们再来看看上面的例子,我想将颜色向量传递给C函数。由于这个操作会频繁进行,所以我不想每一次都分配和释放缓冲区。另一种方法是设计一个额外的C函数,如下所示:

float*wrjs_array3(floatelement0,floatelement1,floatelement2){staticfloatarray[3];array[0]=element0;array[1]=element1;array[2]=element2;returnarray;}

这个函数可以接收三个单独的元素(在这个例子中为颜色),并返回一个指向包含这些元素的静态数组的指针。然而,这种方式也有一些缺点。例如,仅适用于预定义大小的数组,并且一次只能有一个(颜色)数组。

OpenGL

这个问题的原因是Webots使用的是OpenGL3.3,而在Web上我们使用的是WebGL2。WebGL2是OpenGL3.3的对应版本,但二者并不完全相同。此外,Emscripten使用OpenGLES3编译函数,这与OpenGL3.3也略有不同。

这意味着,WebGL2中不包含部分OpenGL3.3中的函数,或者OpenGL3.3和WebGL2中都存在的某个函数,却不包含在OpenGLES3中。或者三个版本都有某个函数,但接收的参数却不相同。

如何解决这些问题?

我没有找到通用的解决方案,如下是我使用过的一些技巧:

建议结果

从Three.js到WebAssembly,编译渲染引擎的转变极大地提高了Web模拟的图形质量。

通过以下图形可以看出桌面版、使用Three.js的Web版,以及使用Emscripten编译的渲染引擎的Web版之间的差异。

THE END
1.基于C语言编写一个简单的Web服务器C语言C语言可以干大事,我们基于C语言可以完成一个简易的Web服务器。当你能够自行完成web服务器,你会对C语言有更深入的理解。对于网络编程,字符串的使用,文件使用等等都会有很大的提高。 关于网络的TCP协议在这里不在多说,大家可以查阅些资料。 工具 开发工具: CLion,编译器 演示效果图 创建socket对象 1 2 3 4 5 6https://www.jb51.net/program/3173974wj.htm
2.C++Webserver从零开始全流程记录对于想走cpp后端开发的同学来说,webserver真的是非常经典的项目,可以说是必做的项目,可以学到的知识太多太多,和纯靠看书看视频完全不一样。做这个项目给我的体验是,我在这个过程中学习的越多,我不懂的就越多。也正是因为这样,才能一直有一股力量在支撑,我要把这个弄懂,这个信念支持着我一直做下去。我觉得,这https://blog.csdn.net/qq_52313711/article/details/136356042
3.redis在yml中配置关闭mob64ca1404baa2的技术博客Web 开发分类 各种数据库对比 NoSQL 数据库 Memcache 和 Redis 的区别? 其它数据库 Redis 简介与安装 Redis 简介 Redis 应用场景 Redis 的下载 Redis 的安装 Redis 的启动 Redis 前台启动(不推荐) Redis 后台启动 Redis 的相关知识 Redis 常用五大数据类型 https://blog.51cto.com/u_16213635/12097620
4.狼叔:Node全栈为前端带来更多可能整体来看,Node.js 在企业 Web 开发领域日渐成熟,无论微服务,还是 Api 中间层都得到了非常好的落地。2017 年,唯一遗憾的是 Node.js 在 servless 上表现的不太好,相关框架实践偏少。 c)不可不见的 Api 中间层 前端越来越复杂,后端服务化,今日的前端要面临更多的挑战。一个典型的场景就是在服务化架构里,前端https://www.infoq.cn/article/node-full-stack-bring-more-possibility
5.的WEB服务器,支持C/C++PythonJava等多语言混合开发WEB应用。cppweb在读数据采用epoll网络模型,以任务队列的方式处理具体请求,回包也在任务队列中处理,理论上cppweb可支持单机10000个以上的并发连接。 cppweb易拓展,作者开发Java、Python等模块,用于支持Java、Python等语言开发cgi程序,开发者可以直接使用C/C++、Java、Python等语言进行混合开发。 https://gitee.com/wangkai0_0/cppweb
6.java从入门到精通java语言程序设计javaweb框架开发教程华C语言程序设计从入门到精通 零基础自学C语言编程入门教程 java从入门到精通 java语言程序设计 java web框架开发教程 华研教育明日科技 C语言程序设计从入门到精通 零基础自学C语言编程入门教程 java从入门到精通 java语言程序设计 java web框架开发教程 分享https://h5.youzan.com/v2/goods/277l3r9wjcx0i
7.C/CWeb框架很明显,这个框架比较的麻烦,但是就是有这些开发人员,它们坚持信念,非要完成似乎是不可能的事情。没有人怀疑C++的力量,但是没有人相信C++能够在Web的上层能够做得更好(虽然以前甚至现在还有人在用C/C++ CGI, 但是我可以想象你痛苦的表情),至少现在没有象Java和.NET那样。注定C/C++是做低层的吗?http://www.360doc.com/content/18/0701/15/6828497_766851335.shtml
8.用C一步步开发web服务器(1)对于php程序员,对于web服务器来说再熟悉不过了,apache,nginx。。但是内心一直想开发出一个属于自己的web服务器,所以借此机会,用c开发出了一款web服务器。作为1.0版本,他实现了以下功能 完成基础的tcp连接,支持基础的client与其连接 使用fork()来支持并发访问服务器 https://www.jianshu.com/p/ef6f07585b7c
9.c做网站(手把手教你做网站)网站制作知识资讯如果想要使用C++来开发Web应用程序,则需要掌握以下技能: 熟悉C++编程语言及其相关框架和库。 了解Web服务器端相关知识,如HTTP协议、Socket网络编程等。 熟悉数据库设计及操作,并掌握SQL语言。 具备前端开发知识,如HTML、CSS、JavaScript等。 C++做网站的实现方式 https://www.semjishu.com/5452.html
10.Avatar——元宇宙和Web3的超级入口拥有一个元宇宙通用avatar或将成为未来普通用户进入web3世界体验的第一站,开发类似模拟人生的游戏化机制来引导新手使用defi,nft产品,而不再进行晦涩难懂的链上交互帮助web3走向主流。 c. 社区&营销 从运营角度说avatar, 虚拟人项目的成功大部分是归功于社区和运营。通过brand & community可以找到最初的种子用户,凝聚https://www.panewslab.com/zh/articledetails/8r628qab.html
11.Python教学Web开发教学全栈开发教学C语言教学汇编教学Win鱼C工作室为大家提供最有趣的编程视频教学。http://www.fishc.com/
12.C++应用软件开发从入门到精通详解其中,Visual Studio 2010是比较经典的版本,这个版本比较稳定且使用流畅,很多公司都在用这个版本,但该版本距今已经有10多年了,很多开源的C/C++代码已经不再支持。比如著名的WebRTC库最低只支持到Visual Studio 2017,已经不再支持Visual Studio 2010了。很多公司为了使用新版本的开源库,为保持库与库之间开发工具的统一http://www.zsrm.cn/news/165779.html
13.奉贤区2022年“人人乐业”周五微聘会,为你而来3、具备视频监控平台或视频联动开发经验; 4、熟练使用Java框架和工具,如Spring boot、Spring Cloud、SpringMVC、Struts、Hibernate、Mybatis等; 5、熟悉数据清洗原理并熟练掌握相关优化方案,熟悉数据库设计,熟练掌握SQL语句。 Web前端开发 人数:2人 月薪:10000-18000元/月 https://www.jfdaily.com/sgh/detail?id=673886
14.Python教学Web开发教学全栈开发教学C语言教学汇编教学Win『用Python做植物大战僵尸』作品展示 纳尼!「FishC」AI小助手来啦!!学习/娱乐/排忧解难 必备佳品~ 【II】请用一行代码找出猪队友 Python爬取B站视频+抓包过程分享 新手必备的 Python 语法总结图|【鱼C特供】 Pygame: 康威生命游戏 【I】添加一行代码,提高10000倍以上的执行效率 https://fishc.com.cn/
15.C设计讲解C语言程序辅导讲解解析C讲解国外C辅导Web开发C设计讲解、C语言程序辅导讲解、解析C、讲解国外C辅导Web开发|调试Matlab程序程序辅导http://www.7daixie.com/2018070210833171.html
16.java中间代码生成器java自动生成代码工具java代码生成器能生成c语言代码吗?用什么方法能实现呢? 按照我的理解,可以的,代码生成器是跨平台,而且是跨语言的(至少是跨文本语言的,UML暂时不好说,)。 代码生成器作为一种开发工具,一般不直接作为程序的一部分,通常也不直接或间接(如通过AOP)被程序调用,他是通过编程的方式生成所需要的代码,然后将生成的代码https://www.xiuzhanwang.com/a1/JavaScript/17047.html
17.Web程序基本概念从事后端开发的Java程序员,目前技术栈主要涉及Java、SQL、Spring MVC、MyBatis等。 4.开发Web应用程序需要解决的三个基本问题 (1)如何将信息呈现给用户以及如何引导用户提交信息 (2)在服务器端如何获取及处理用户提交的信息 (3)在服务器端如何与数据库交互 5.C/S架构 6.B/S架构https://cooc.cqmu.edu.cn/Course/KnowledgePoint/15742.aspx
18.Linux超macOS最讨厌Angular.js框架,调查了7万名开发者的近日,全球知名程序员问答社区 Stack Overflow 对来自全球 180 个国家/地区的 73268 名软件开发者调查后,重磅发布了《2022 Developer Survey》报告,剖析当代开发者如何学习与升级技能,以及正在使用的工具现状。在此,也希望疾步行走中的大家不妨适当停下脚步看看当前的整体开发趋势。https://36kr.com/p/1797480144044544
19.今晚七点metaRTC的发展和应用嘲探讨腾讯云开发者社区点击上方“LiveVideoStack”关注我们 metaRTC是一个自主研发的支持WebRTC/Srt/Rtmp的RTC SDK库,包含多种视音频编解码和处理等,在安防监控、直播、视频会议等方面有较广泛的应用。同时,metaRTC3.0将在近期形成稳定版本,metaRTC将进入4.0时代。4月21日晚七点,我们邀请到了metaRTC作者、WebRTC自主研发资深专家 杨高https://cloud.tencent.com/developer/article/1985859