文章目录
- 概要
- 前期准备
- QT 与 Unity 的 Socket 通信
- 实际应用场景
- 总结
概要
在 VR 开发中,常常需要桌面窗口和 VR 头盔使用者进行交互。通过将 Unity制作的 VR 程序嵌入到 QT 应用程序窗口中,并使用 Socket进行通信,可以实现这种交互。本文将介绍如何实现这一功能。
前期准备
- Unity 项目打包 首先,在 Unity 中开发并打包您的项目为可执行文件(EXE)。确保您已经测试过独立运行的 EXE 并且一切正常。
- QT 环境设置 安装并配置好 QT 开发环境。如果您还没有 QT 安装,可以访问 QT 官方网站 下载和安装。
QT 与 Unity 的 Socket 通信
- QT 服务器设置 在 QT 中,使用 QUdpSocket 创建一个 UDP 服务器来接收来自 Unity 的数据,在QT程序初始化时用QProcess启动Unity程序,并且等待Unity程序连接,Unity程序连接后获取Unity程序的窗口句柄,并把这个窗口嵌入到QT中:
#include <QPushButton>
#include <QVBoxLayout>
#include <QtNetwork>
#include "QProcess"
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr) : QMainWindow(parent)
{
QUdpSocket* socket = new QUdpSocket(this);
socket->bind(QHostAddress("127.0.0.1"), 6060);
connect(socket, SIGNAL(readyRead()), this, SLOT(readData()));
QProcess* process = new QProcess(this);
QString cmd = "path/to/your/VRUnityApp.exe";
process->start(cmd, QStringList() << "");
QVBoxLayout *layout = new QVBoxLayout;
QWidget *centralWidget = new QWidget(this);
centralWidget->setLayout(layout);
setCentralWidget(centralWidget);
QPushButton *switchSceneButton = new QPushButton("Switch Scene", this);
QPushButton *createObjectButton = new QPushButton("Create Object", this);
layout->addWidget(switchSceneButton);
layout->addWidget(createObjectButton);
connect(switchSceneButton, &QPushButton::clicked, [server]() {
sendData("switch_scene");
});
connect(createObjectButton, &QPushButton::clicked, [server]() {
sendData("create_object");
});
}
void sendData(const QString& data)
{
for (int i = 0; i < m_client.count(); i++) {
QString str = m_client.at(i);
QStringList list = str.split(":");
QByteArray buffer;
buffer = data.toUtf8();
socket->writeDatagram(buffer, QHostAddress(list.at(0)), list.at(1).toInt());
}
}
void OnDataRecived(const QString& msg)
{
if (msg == "Connect")
{
WId wid = (WId)FindWindow(L"XXXXX", NULL);//获取窗口句柄
m_window = QWindow::fromWinId(wid);
m_window->setFlags(m_window->flags() | Qt::CustomizeWindowHint | Qt::WindowTitleHint);
QWidget* m_widget;
m_widget = QWidget::createWindowContainer(m_window, this);
ui->containerWidget->layout()->addWidget(m_widget);
}
}
private slots:
void readData()
{
QHostAddress host;
quint16 port;
QByteArray data;
QString buffer;
while (socket->hasPendingDatagrams()) {
data.resize(socket->pendingDatagramSize());
socket->readDatagram(data.data(), data.size(), &host, &port);
buffer = QString(data);
OnDataRecived(buffer);
QString ip = host.toString();
ip = ip.replace("::ffff:", "");
if (ip.isEmpty()) {
continue;
}
QString str = QString("[%1:%2] %3").arg(ip).arg(port);
//先过滤重复的
str = QString("%1:%2").arg(ip).arg(port);
for (int i = 0; i < m_client.count(); i++) {
if (str == m_client.at(i)) {
return;
}
}
//添加到列表
m_client.push_back(str);
}
}
};
- Unity 客户端设置 在 Unity 中,使用 System.Net.Sockets.UdpClient 创建一个 UDP 客户端,并向 QT 服务器发送数据:
public class UnityClient : MonoBehaviour
{
private UdpClient client;
void Start()
{
client = new UdpClient();
SendMessageToServer("Connect");
client.BeginReceive(OnReceive, null);
}
void SendMessageToServer(string message)
{
byte[] data = Encoding.UTF8.GetBytes(message);
client.Send(data, data.Length, "127.0.0.1", 12345);
}
private void OnReceive(IAsyncResult ar)
{
IPEndPoint endpoint = new IPEndPoint(System.Net.IPAddress.Any, 54321);
byte[] data = client.EndReceive(ar, ref endpoint);
string command = Encoding.UTF8.GetString(data);
Debug.Log("Received command: " + command);
// 根据命令执行相应的操作
if (command == "switch_scene")
{
SwitchScene();
}
else if (command == "create_object")
{
CreateObject();
}
// 继续接收下一个命令
client.BeginReceive(OnReceive, null);
}
void SwitchScene()
{
// 切换到另一个场景
SceneManager.LoadScene("AnotherScene");
}
void CreateObject()
{
// 创建一个简单的游戏物体
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.transform.position = new Vector3(0, 1, 0);
}
void OnDestroy()
{
client.Close();
}
}
此脚本在 Unity 中启动时会向 QT 服务器发送一条消息。QT收到消息后会获取Unity程序的窗口句柄,并把这个窗口嵌入到QT中
实际应用场景
通过上述设置,QT 程序可以在桌面上实时控制 VR 场景中的行为,例如切换场景或创建游戏物体。这种交互方式适用于各种需要实时控制 VR 场景的应用场景,比如 VR 培训、虚拟展览等。
总结
本文详细介绍了如何通过 QT 服务器向 Unity VR 程序发送命令,以实现场景切换和游戏物体创建等交互功能。通过 UDP 进行通讯,您可以实现桌面和 VR 头盔之间的无缝互动,提升用户体验。如果您在实施过程中遇到问题或有其他需求,欢迎交流讨论。