当前位置:首页 > 每日看点 > 正文内容

为什么c#能做大型游戏,而java不适合,c#跟java不是很相似吗?

卡卷网10个月前 (12-29)每日看点140

就说个编写 3D 游戏里最常见的场景吧。

现在我想要渲染一个 3D 模型,需要将组成模型的面传递给游戏引擎,然后引擎会去调用 DirectX/Vulkan/OpenGL 等等的 API 将我们模型数据提供给 GPU 渲染出来。

我们都知道 3D 模型的面由三角形组成,而每个三角形都有 3 个顶点,最后一大堆三角形组成了整个模型的表面。

那这件事情要怎么做呢?最简单的方法:整一个缓冲区把三角形的各顶点的位置存起来,然后调用图形 API 把数据上传到 GPU 就行了。

那这件事情在 C# 里面怎么做呢?

首先定义顶点类型:

[StructLayout(LayoutKind.Sequential)] record struct Vertex(float X, float Y, float Z);

然后我们整个顶点数组:

var vertices = new Vertex[12345];

然后把我们的三角形扔进去之后直接扔给引擎就完事了。

填充的时候简单 for 循环里往 vertices 里塞 Vertex 就行了。

假设引擎用的 OpenGL,那此时引擎接收到我们的数组后需要调用 glBufferData 来给 VAO 提供顶点数据:

const uint GL_ARRAY_BUFFER = 0x8892; const uint GL_STATIC_DRAW = 0x88E4; fixed (Vertex* p = vertices) glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * vertices.Length, p, GL_STATIC_DRAW);

glBufferData 这个函数要怎么在 C# 里定义呢?

[DllImport("glew32.dll", EntryPoint = "__glewBufferData"), SuppressGCTransition] static extern void glBufferData(uint target, nint size, void* data, uint usage);

搞定。

至此为止我没有用到任何的(除了 OpenGL 本身之外的)库,也没有编写任何的 C# 以外的代码。

那写法这么简单,性能怎么样呢?我们看看最终调用 glBufferData 的部分 JIT 给我们生成了什么代码:

add rax, 16 ; address of vertices + method table (8) + array length (8) mov r8, rax ; = data of vertices mov edx, 0x242AC ; sizeof(Vertex) * vertices.Length mov ecx, 0x8892 ; GL_ARRAY_BUFFER mov r9d, 0x88E4 ; GL_STATIC_DRAW mov eax, 0x5B589850 ; function pointer of glBufferData call rax ; call glBufferData

可以看到,没有任何额外的内存分配和开销,数据直接从指针传出去,压根不需要拷贝,从头到尾的零成本抽象。

甚至可以说 C# 就是一个可以用 GC 的现代版 C++,这对于需要频繁与 native 进行交互的场景而言最适合不过。更不要提 C# 的 P/Invoke 在 NativeAOT 之下支持静态链接,连额外的 dll 都省了。


以上东西你用 Java 做一个试试,看看能有多复杂,再看看填充 buffer 的时候能否直接利用定义好的数据结构和类型,再看看能不能做到零拷贝。


更新:

鉴于 Java 22 之后有了 FFM API,以上东西虽然做起来很麻烦,但是好歹能写出来了,虽然我不知道他们现在的 FFM API 打算如何支持静态链接,毕竟 Java FFM API 这种运行时定义布局和查找入口点跟静态链接就是天生不兼容的。


那我们现在进一步加大难度。

我们都知道给 GPU 送的数据不一定非得是 float ,还可以是 intdouble 等等。那此时在 C# 里面我们只需要把顶点类型改成:

[StructLayout(LayoutKind.Sequential)] record struct Vertex<T>(T X, T Y, T Z) where T : unmanaged;

然后调用 glBufferData 那句改成:

fixed (Vertex<T>* p = vertices) glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex<T>) * vertices.Length, p, GL_STATIC_DRAW);

就搞定了。

由于 .NET 会针对泛型参数给代码进行特化,因此 T 无论是 intfloat 还是 double,甚至是更复杂的类型例如 record struct Foo<U>(Bar A, float B, U C) 都能获得独一无二的代码生成,并且其内存布局也是编译时就确定的,效率也有保证。

扫描二维码推送至手机访问。

版权声明:本文由卡卷网发布,如需转载请注明出处。

本文链接:https://www.kajuan.net/ttnews/2024/12/5894.html

分享给朋友:

相关文章

CDN评测,阿里云有对手了!腾讯云优势明显

CDN评测,阿里云有对手了!腾讯云优势明显

         如今,云计算产品越来越多,像国内的BAT三大巨头都提供了云主机(腾讯云CVM、阿里云ECS、百度云BCC),另外还有存储、数据库、安全等相关云服务。在这其中,CDN也是一项重要的云服...

普通人一部手机用多久?

普通人一部手机用多久?

各位知友,你们的现在的手机用了多久了呢?回看国外分析机构TechInsights的报告,目前大家的用机周期是越来越长了,在国内,也达到了「40个月」,就是很多人至少三年半才会换一次手机。仔细想想,不对呀,现在新机不是一直出吗?为什么大家都不...

抖音和快手最大的区别是什么?

1、目标人群定位不同抖音:一二线城市,占比52%,大专学历以上,女性偏多。抖音以年轻群体居多。快手:三四线城市,占比64%,高中学历以下,男女更均衡。快手所覆盖的年龄段范围更广。2、内容创作的形式和深度不同抖音:偏深层,内容的装饰及表达更高...

夸克浏览器受欢迎的原因是什么?

夸克浏览器受欢迎的原因是什么?

这是可以说的嘛~哈哈,它比较吸引我的几点是:安全无广、页面简洁、功能丰富、反应速度快......首页页面支持自定义,喜欢什么样子都可以自己调整,没有花里胡哨的各种资讯推送,热搜日报整理归纳好,想看再点开查看,看着舒适度直接拉满!实用日常工具...

怎样拥有一台最便宜的服务器?

怎样拥有一台最便宜的服务器?

内容提示:主打一个 DIY + 极限白嫖 =)某宝花10块买一个“随身WiFi”,刷入Ubuntu,用SSH远程连接,但是记得一定要把外壳撬掉然后粘个散热器(哪怕是白萝卜也彳亍),否则会过热详细去酷安社区搜“随身WiFi”=========...

国内AI大模型已近80个,哪个最有前途?

国内AI大模型已近80个,哪个最有前途?

题主说错了,不是80个,是168个!虽然“最有前途”不好说,但是我可以帮题主排除一些错误方向:开源大模型一定比闭源的有前途吗?参数量大的模型一定就比小模型有前途吗?榜单排名高的大模型一定更有前途吗?2024年3月更新,243个大模型中有哪几...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。