如果你想节省韶光,你可以试试虚幻商城上任何二维码插件的运气。但这些插件普遍缺少评论,同时作为程序员的骄傲阻挡了我抛出50欧元。
下面是我的研究步骤:
就像你可能期望的那样,我的旅程始于网络搜索“C++QR code”。第一个结果得出了这样的结果:

事实上,这个拥有1600颗星的GitHub仓库从一开始就看起来很有希望。此外,文档简明扼要,主要的是,包含大略的示例。
因此,我连续心不在焉地将CPP文件(QrCode.hpp和QrCode.cpp)复制到虚幻项目的代码文件夹中。这对我来说总是关键时候。它会编译吗?或者,我将不得不在神秘的C++缺点上撕掉我的头发。幸运的是,它编译没有任何问题。
按照网站上的例子和一些基本的虚幻C++知识,打算QR码就像馅饼一样大略:
UTexture2D UWebBuzzers::GenerateQrCode(UObject parent, FString string){ auto errorCorrectionLevel = qrcodegen::QrCode::Ecc::LOW; qrcodegen::QrCode qr = qrcodegen::QrCode::encodeText(TCHAR_TO_UTF8(string), errorCorrectionLevel); uint8 size = qr.getSize(); TArray<FColor> pixels; pixels.SetNumZeroed(size size); FColor black = FColor::Black; FColor white = FColor::White; for (uint8 x = 0; x < size; x++) { for (uint8 y = 0; y < size; y++) { FColor color = qr.getModule(x, y) ? white : black; pixels[x + y size] = color; } } // TODO: Generate texture from color array (see below)}
实际的QR打算发生在对 encodeText 的一次调用中。请把稳,我选择大略地利用低纠错级别,这使得QR码更小。这是由于在屏幕上显示QR码不太可能受到障碍物或失落真的太大影响。
这非常大略直不雅观。向Nayuki致敬,为这个伟大的库而欢呼!
下一步是将该颜色数组转换为可以显示的纹理。这乃至更大略,至少在一开始是这样:
FCreateTexture2DParameters params; UTexture2D texture = FImageUtils::CreateTexture2D(size, size, pixels, parent, "QRCode", EObjectFlags::RF_Transient, params); // don't interpolate texels to get sharp edges (otherwise the image would look blurry) texture->Filter = TextureFilter::TF_Nearest;
我正在利用FImageUtils: CreateTexture2D在运行时天生纹理。它的文档极度短缺示例代码,就像全体虚幻文档一样。但我终极想出了一组有效的参数:
前两个参数只因此像素为单位的大小,我大略将其设置为QR码的大小(“模组”的数量)像素是上面的 FColor 数组parent是任何可以传入的 UObject工具,例如通过蓝图。这很主要!如果没有设置 parent,纹理将立即被垃圾回收,或者至少我认为这是正在发生的事情。不设置它将导致编辑器崩溃并涌现诸如“工具未打包”之类的缺点。QRCode是纹理的名称,可以自由选择对付 flags,我不太确定这里须要通报什么。但根据稀疏的文档 我选择RF_Transient - “不保存工具”,由于纹理只该当在运行时存在。末了一个参数 params 许可变动其他一些我什么都不知道的选项,以是我将它们保留为默认值。
将纹理滤镜设置为 NEAREST(最近邻插值)也很主要。默认滤镜在像素之间利用某种插值,这意味着当纹理被拉伸时,它会变得非常非常模糊。天生的纹理大小仅在 17×17 和 144×144 像素之间,详细取决于编码字符串的长度和纠错级别。
在编辑器中完美运行。我们完成了,对吧?恐怕不是。虽然此代码在编辑器中按预期运行,但它实际上会在打包的构建中崩溃,并涌现以下缺点:“掌握台不支持布局texture2D”,正如我刚刚创造的那样。
这个办理方案并不俊秀,虚幻的文档再次毫无帮助。以是回到网络搜索。不幸的是,论坛或“AnswerHub”上关于虚幻引擎的许多问题都没有得到解答。Unity社区彷佛处于更好的状态。无论如何,我终极找到了一个带有办理方案的帖子(只管没有阐明):
UTexture2D texture = UTexture2D::CreateTransient(size, size, EPixelFormat::PF_B8G8R8A8, "QRCode"); void data = texture->PlatformData->Mips[0].BulkData.Lock(LOCK_WRITE); FMemory::Memcpy(data, pixels.GetData(), size size 4); texture->PlatformData->Mips[0].BulkData.Unlock(); texture->UpdateResource();
作为一个之前利用DirectX和OpenGL编写C++程序的人,对付“掌握台”不支持初始办理方案这个问题,我依然没有任何线索,。大概是由于非方形的纹理大小,但我
无论如何,这是终极代码(另请参阅此Gist):
#include "QrCode.hpp" // from https://github.com/nayuki/QR-Code-generator#include "ImageUtils.h" // from Unreal Engine (4.24)/// <summary>Generates a QR code texture from a string.</summary>/// <param name="parent">UE parent (required)</param>/// <param name="string">String to encode</param>UTexture2D UWebBuzzers::GenerateQrCode(UObject parent, FString string){ qrcodegen::QrCode qr = qrcodegen::QrCode::encodeText(TCHAR_TO_UTF8(string), qrcodegen::QrCode::Ecc::LOW); uint8 size = qr.getSize(); TArray<FColor> pixels; pixels.SetNumZeroed(size size); FColor black = FColor::Black; FColor white = FColor::White; for (uint8 x = 0; x < size; x++) { for (uint8 y = 0; y < size; y++) { FColor color = qr.getModule(x, y) ? white : black; pixels[x + y size] = color; } } UTexture2D texture = UTexture2D::CreateTransient(size, size, EPixelFormat::PF_B8G8R8A8, "QRCode"); void data = texture->PlatformData->Mips[0].BulkData.Lock(LOCK_WRITE); FMemory::Memcpy(data, pixels.GetData(), size size 4); texture->PlatformData->Mips[0].BulkData.Unlock(); texture->UpdateResource(); texture->Filter = TextureFilter::TF_Nearest; return texture;}
我在这里没有展示的是,我将此函数作为蓝图代码库的一部分公开。如何做到这一点,我不打算在这里先容,由于这是一种标准的虚幻的东西,该当被文档所涵盖。
3. 利用Image在 UI 中显示该纹理要在UI中显示天生的QR码纹理,只需抓取图像,从上面调用蓝图函数,并利用“从纹理设置画笔”将结果设置为图像的纹理。
大功告成!
这便是你在虚幻引擎中天生和显示QR码的办法,就像一个对虚幻引擎险些一无所知的人一样。如果有一天我学会了更好的方法来做到这一点,我会确保更新这篇文章。
原文链接:http://www.bimant.com/blog/ue4-qrcode/