夜風のMixedReality

xRと出会って変わった人生と出会った技術を書き残すためのGeekなHoloRangerの居場所

Blenderでサーバーを立ててUnityへデータを送信する

本日はBlenderモデリング枠+Unity枠です。

先日Blenderでサーバーを立ててUnityからBlenderへデータを飛ばすことを行いました。

redhologerbera.hatenablog.com

今回は逆にBlenderからUnityに対してデータを送信することを行っていきます。

今回はサンプルとして現在のポリゴン数を送信してUnityのログに表示させていきます。

〇現在のポリゴン数を取得

シーン内のポリゴン数を取得するためには次のようなコマンドを使用します。

  def execute(self, context):
        # 全オブジェクトのポリゴン数を集計する
        total_polygons = sum([len(obj.data.polygons) for obj in bpy.context.scene.objects if obj.type == 'MESH'])

この処理を詳しく分解すると次のようになります

polygon_counts = []  # ポリゴンの数を保持するリスト

# シーン内の全オブジェクトに対してループ
for obj in bpy.context.scene.objects:
    if obj.type == 'MESH':
        polygon_counts.append(len(obj.data.polygons))

for文でシーン内にあるすべてのオブジェクトの数ループします。 もしオブジェクトのタイプがメッシュである場合はpolygon_countsにそのオブジェクトが持つポリゴン数を追加します。(obj.data.polygons)

これを使用して作成したBlenderのコードが次になります。

〇Blenderのコード

import bpy
import socket
import threading

# Unity側のサーバーアドレスを設定する
unity_address = ('Unity実行PCのIPアドレス', 5006)

def server_thread(sock):
    # データを受信する
    while True:
        data, address = sock.recvfrom(4096)
        if not data:
            break

        # 受信したデータを表示する
        print(f'Received data from {address}: {data.decode()}')

class SendPolygonsOperator(bpy.types.Operator):
    bl_idname = "wm.send_polygons"
    bl_label = "Send Polygons"

    def execute(self, context):
        # 全オブジェクトのポリゴン数を集計する
        total_polygons = sum([len(obj.data.polygons) for obj in bpy.context.scene.objects if obj.type == 'MESH'])

        # ポリゴン数を送信する
        sock.sendto(str(total_polygons).encode(), unity_address)

        return {'FINISHED'}

def register():
    bpy.utils.register_class(SendPolygonsOperator)

    # キーマップを作成する
    wm = bpy.context.window_manager
    km = wm.keyconfigs.addon.keymaps.new(name='Object Mode', space_type='EMPTY')

    # 「P」キーが押されたときにSendPolygonsOperatorを呼び出すように設定する
    kmi = km.keymap_items.new(SendPolygonsOperator.bl_idname, 'P', 'PRESS')

register()

# ソケットを作成する
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# サーバーアドレスを設定する
server_address = ('Blender実行CPのIpアドレス', 5005)
sock.bind(server_address)

# サーバースレッドを作成して開始する
t = threading.Thread(target=server_thread, args=(sock,))
t.daemon = True
t.start()

このコードではBlenderのビューポートでPキーを入力することでUnity側に現在のポリゴン数を送信します。

〇Unity側の実装

Unity側では、次の関数でログを受け取ることができます。

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using UnityEngine;

public class ReceiveBlenderData : MonoBehaviour
{
    UdpClient udpClient;
    IPEndPoint endPoint;

    private void Start()
    {
        udpClient = new UdpClient(5006); // Blenderからのデータを受信するポート番号
        endPoint = new IPEndPoint(IPAddress.Any, 0);
        BeginReceive();
    }

    private void BeginReceive()
    {
        udpClient.BeginReceive(ReceiveCallback, null);
    }

    private void ReceiveCallback(IAsyncResult ar)
    {
        byte[] receivedBytes = udpClient.EndReceive(ar, ref endPoint);
        string receivedString = Encoding.UTF8.GetString(receivedBytes);

        Debug.Log("Received data: " + receivedString);

        BeginReceive(); // 続けてデータを受信するために再度BeginReceiveを呼び出す
    }

    private void OnDestroy()
    {
        udpClient.Close();
    }
}

これを実行することで次のようなログを得ることができます。

以上でBlenderでサーバーを立ててUnityへデータを送信することもできました。