为什么多数游戏服务端是用 C++ 来写呢,是历史原因还是性能方面的考虑?

用 C++ 是历史原因还是性能方面的考虑?感觉 C++ 开发效率相对较低,对开发人员的要求也高,用 C++ 写出一个健壮的服务端确实比较难,为什么很多游戏服务端要用 C++ 来实现?是因为普遍写服务端的前辈是 C++ 出身么,还是说对于游戏服务端来说 C++ 的性能赶超其他语言一大截或者有其他优势,如果不是,现在用什么语言来开发 MMORPG 比较合适呢?
感谢大家。

有一个场景:

玩家和怪物之间隔了一堵墙,怪物能看见玩家吗?这就需要可见性判断了。可见性判断的方法就是光线追踪,即从怪物向玩家发出一条射线,如果击中了玩家,就表明怪物可以“看见”玩家,同时玩家也可以“看见”怪物。只有玩家与怪物互相可以看见,中间没有遮挡障碍物的情况下,服务器才会向玩家的客户端发包,更新怪物的坐标信息。

光线追踪,就是求出用光线是否与AABB盒,三角形相交。如果相交,就求出xy坐标(AABB盒),重心坐标(三角形)。

做光线追踪,就要建造相应的数据结构,基本上所有的光线追踪渲染器都用BVH。用SAH或Morton Code方法建造。静态场景(地形,建筑)建造一棵,动态场景(人物)建造一棵就行了。在建造BVH过程中会有大量的max min计算,可以用SIMD指令 _mm_max_epi32 _mm_min_epi32计算,一次可以计算4个max min。

另一种光线追踪的方式是针对高度场(如地形)的,具体方法可以参考视差映射贴图。

追求现成的可以使用开源的库比如Intel的embree,支持AVX512SKX指令集,优化的特别好。关于性能,我家的i7-2600k 每秒约25M射线,足够了。

embree 渲染 Cornell Box

这是一个embree的简单Demo,只包含射线相交,不包括显示。

#include "pch.h"#include <iostream>#include <embree3/rtcore.h>#include <DirectXMath.h>#include<assert.h>

struct Triangle { int v0, v1, v2; };

int main(){RTCDevice device = rtcNewDevice("tri_accel=bvh4.triangle4v");RTCError error = rtcGetDeviceError(device);assert(error == RTCError::RTC_ERROR_NONE);RTCScene scene = rtcNewScene(device);RTCGeometry mesh = rtcNewGeometry(device, RTC_GEOMETRY_TYPE_TRIANGLE);

DirectX::XMFLOAT3A pos;pos.x = 0.0f;pos.y = 0.0f;pos.z = 0.0f;

DirectX::XMFLOAT3A* vertices = (DirectX::XMFLOAT3A*)rtcSetNewGeometryBuffer(mesh, RTC_BUFFER_TYPE_VERTEX, 0, RTC_FORMAT_FLOAT3, sizeof(DirectX::XMFLOAT3A), 8);vertices[0].x = pos.x + -1; vertices[0].y = pos.y + -1; vertices[0].z = pos.z + -1;vertices[1].x = pos.x + -1; vertices[1].y = pos.y + -1; vertices[1].z = pos.z + +1;vertices[2].x = pos.x + -1; vertices[2].y = pos.y + +1; vertices[2].z = pos.z + -1;vertices[3].x = pos.x + -1; vertices[3].y = pos.y + +1; vertices[3].z = pos.z + +1;vertices[4].x = pos.x + +1; vertices[4].y = pos.y + -1; vertices[4].z = pos.z + -1;vertices[5].x = pos.x + +1; vertices[5].y = pos.y + -1; vertices[5].z = pos.z + +1;vertices[6].x = pos.x + +1; vertices[6].y = pos.y + +1; vertices[6].z = pos.z + -1;vertices[7].x = pos.x + +1; vertices[7].y = pos.y + +1; vertices[7].z = pos.z + +1;

int tri = 0;Triangle* triangles = (Triangle*)rtcSetNewGeometryBuffer(mesh, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, sizeof(Triangle), 12);

// left sidetriangles[tri].v0 = 0; triangles[tri].v1 = 2; triangles[tri].v2 = 1; tri++;triangles[tri].v0 = 1; triangles[tri].v1 = 2; triangles[tri].v2 = 3; tri++;

// right sidetriangles[tri].v0 = 4; triangles[tri].v1 = 5; triangles[tri].v2 = 6; tri++;triangles[tri].v0 = 5; triangles[tri].v1 = 7; triangles[tri].v2 = 6; tri++;

// bottom sidetriangles[tri].v0 = 0; triangles[tri].v1 = 1; triangles[tri].v2 = 4; tri++;triangles[tri].v0 = 1; triangles[tri].v1 = 5; triangles[tri].v2 = 4; tri++;

// top sidetriangles[tri].v0 = 2; triangles[tri].v1 = 6; triangles[tri].v2 = 3; tri++;triangles[tri].v0 = 3; triangles[tri].v1 = 6; triangles[tri].v2 = 7; tri++;

// front sidetriangles[tri].v0 = 0; triangles[tri].v1 = 4; triangles[tri].v2 = 2; tri++;triangles[tri].v0 = 2; triangles[tri].v1 = 4; triangles[tri].v2 = 6; tri++;

// back sidetriangles[tri].v0 = 1; triangles[tri].v1 = 3; triangles[tri].v2 = 5; tri++;triangles[tri].v0 = 3; triangles[tri].v1 = 7; triangles[tri].v2 = 5; tri++;

rtcCommitGeometry(mesh);

unsigned int geomID = rtcAttachGeometry(scene, mesh);rtcReleaseGeometry(mesh);

rtcCommitScene(scene);

RTCIntersectContext context;rtcInitIntersectContext(&context);

RTCRayHit rayhit;memset(&rayhit, 0, sizeof(rayhit));rayhit.ray.org_x = 0.0f;rayhit.ray.org_y = 10.0f;rayhit.ray.org_z = 0.0f;rayhit.ray.tnear = 0.0f;rayhit.ray.tfar = 100.0f;rayhit.ray.time = 0.0f;rayhit.ray.mask = -1;rayhit.ray.dir_x = 0.0f;rayhit.ray.dir_y = -1.0f;rayhit.ray.dir_z = 0.0f;

rtcIntersect1(scene, &context, &rayhit);

std::cout << rayhit.hit.Ng_x<< " "<< rayhit.hit.Ng_y<< " "<< rayhit.hit.Ng_z<< " "<< rayhit.hit.u<< " "<< rayhit.hit.v<< " "<< rayhit.hit.primID<< " "<< rayhit.hit.geomID<< " "<< std::endl;

rtcReleaseScene(scene);rtcReleaseDevice(device);}

如果需要再快一点,我有一种方法:服务器装块RTX显卡,用DirectX Raytracing(或者用Vulkan,Nvidia的Optix)进行光线追踪,速度能快很多。如果没有RTX显卡,可以使用DirectX Raytracing Fallback Layer 或者自己写一个(本人正在实现中, Fallback Layer就是一个完整的光线追踪实现),基本上所有的显卡都支持,不过性能没有RTX那么高。

RTX2070渲染的sponza,微软的Demo,每秒700M射线

Bullet引擎也可以在GPU上进行光线投射检测,还自带碰撞检测功能,但不支持RTX。可以用一用。

使用光线追踪可以彻底防止透视外挂出现。

服务器把玩家可以看见的其他玩家和怪物坐标信息使用可靠UDP传输库(如raknet,enet)发送给玩家客户端。 坐标不进行出错重传并允许乱序,以达到更低的延迟。

有评论说服务器端可以不用光线追踪,我要问问?如果在服务器端实现像CS那样的bot功能,而且是可以多人游戏的,用什么样的方法判断bot是否能看到玩家?

如果用Java C#之类的语言该怎么实现光线追踪?还有有没有可靠UDP传输库?

免责声明:部分资源收集整理自网络,版权归原作者所有,仅作学习交流使用,不用于任何商业途径,如不慎该资源侵犯了您的权利,请通知我及时删除,谢谢。

(0)

相关推荐