如何使用带有脚本的 godot fbx 导入器

Posted

技术标签:

【中文标题】如何使用带有脚本的 godot fbx 导入器【英文标题】:how to use godot fbx importer with script 【发布时间】:2021-10-14 21:51:32 【问题描述】:

我正在尝试制作一款在线游戏,我想从服务器导入一些 3d 文件,但我不知道如何使用脚本将它们导入到游戏中。

是否可以在服务器端将 fbx 转换为 PoolByteArray 并在客户端再次将其转换为 fbx?

【问题讨论】:

【参考方案1】:

网络代码

基本服务器设置

由于我们想要客户端-服务器并且我们想要发送PoolByteArray,我假设我们正在使用 Godot(而不是其他技术)制作权威服务器。特别是我们将使用MultiplayerAPI

我们可以从NetworkedMultiplayerEnet 类的对象开始。我们将选择一个端口来监听(理想情况下,您可以使其可配置,但这里是硬编码的):

服务器 Server.gd

extends Node

var network := NetworkedMultiplayerENet.new()
var port:int = 1024

func _ready():
    # start server
    var error: = network.create_server(port)
    if error != OK:
        print ("Error Creating Server: ", error)
        return

    get_tree().multiplayer.set_network_peer(network)

基本客户端设置

客户端代码非常相似。除了我们需要提供服务器的地址和端口(这里我硬编码了“127.0.0.1”)。

客户server.gd

extends Node

var network := NetworkedMultiplayerENet.new()
var server_port:int = 1024
var server_address:String = "127.0.0.1"

func _ready():
    # start server
    var error: = network.create_client(server_address, server_port)
    if error != OK:
        print ("Error Connecting to the Server: ", error)
        return

    get_tree().multiplayer.set_network_peer(network)

客户端-服务器连接

我们可以连接MultiplayerAPI"network_peer_connected""network_peer_disconnected"信号:

客户端和服务器Server.gd

get_tree().multiplayer.connect("network_peer_connected", self, "_on_peer_connected")
get_tree().multiplayer.connect("network_peer_disconnected", self, "_on_peer_disconnected")

我们可以在SceneTreeNetworkedMultiplayerEnet 上找到类似的信号。他们都工作。我使用MultiplayerAPI 只是为了保持一致。

无论我们连接的是哪个版本的这些信号,处理程序的外观和行为都相同:

func _on_peer_connected(player_id:int) -> void:
    print("Player Connected with id: ", player_id)

func _on_peer_disconnected(player_id:int) -> void:
    print("Player Disconnected with id: ", player_id)

在客户端上,您应该与player_id1 建立对等连接。那总是服务器。在服务器上,您将获得一个对等连接的信号,该信号带有一个大的player_id 数字,用于标识客户端。如果有多个客户端,它们会相互获取对等连接信号。

同样,当客户端离线时,您将收到对等断开信号。但是,当服务器离线时,客户端不会收到对等断开信号。相反,您会收到 "server_disconnected" 信号。在MultiplayerAPI(和SceneTree)上还有一个"connected_to_server" 信号可用。


通过网络发送PoolByteArray

在服务器上,让我们发送我们的PoolByteArray。例如成功连接:

func _on_peer_connected(player_id:int) -> void:
    print("Player Connected with id: ", player_id)
    get_tree().multiplayer.send_bytes(PoolByteArray([125, 30, 50]), player_id)

您当然会跟踪已连接玩家的 id,并在适当的时候将PoolByteArray 发送给适当的客户端。出于解释的目的,我这样做是这样的。


通过网络接收PoolByteArray

在客户端,我们将连接"network_peer_packet"信号:

get_tree().multiplayer.connect("network_peer_packet", self, "_on_network_packet")

我们将PoolByteArray 作为处理程序的参数:

func _on_network_packet(player_id:int, packet:PoolByteArray) -> void:
    print("Packet from ", player_id)

PoolByteArray 读写文件

阅读PoolByteArray

我们将使用File 类的对象和get_buffer 函数。

func read_file_to_pool_byte_array(path:String) -> PoolByteArray:
    var file = File.new()
    var error = file.open("user://path/to/file", File.READ)
    if error == OK:
        var result:PoolByteArray = file.get_buffer(file.get_len())
        file.close()
        return result
    else:
        print("Error opening the file.")

写信PoolByteArray

func write_file_from_pool_byte_array(path:String, data:PoolByteArray) -> void:
    var file = File.new()
    var error = file.open("user://path/to/file", File.WRITE)
    if error == OK:
        file.store_buffer(data)
        file.close()
    else:
        print("Error opening the file.")

资源序列化

如您所知,您可以使用loadpreloadResourceLoader.loadResourceLoader.load_interactive 加载资源(请参阅Background loading)。

对应的是ResourceSaver。您可以使用ResourceSaver.save 将资源保存到文件中。


FBX?

没有。

导入 FBX 所需的功能只能由编辑器实例化。它不适用于游戏构建。 好的,至少默认情况下它不可用,但启用它需要自定义构建 Godot。除非您想从源代码构建 Godot 以启用它们……那是“否”。


把所有东西放在一起

在 Godot 项目中导入您的 FBX。它作为场景导入。打开它并将其另存为资源格式。那是您要发送的文件,而不是 FBX。

在服务器上:

将资源文件读入PoolByteArray。 将PoolByteArray 发送给客户端。

在客户端:

从服务器接收PoolByteArray。 将PoolByteArray 保存到文件中。 使用ResourceLoader.loadResourceLoader.load_interactive 加载文件,因此您将获得PackedScene

然后您可以在必要时通过调用instance 来实例化PackedScene

因为您将在客户端上存储资源文件。您可以更多地参与解决方案,并让客户端仅在服务器没有资源时才从服务器请求资源。

您甚至可以让服务器告诉客户端文件的哈希值...然后,对于每个文件,客户端可以检查它是否有它,以及哈希值是否匹配(请参阅HashingContext)。如果没有,或者哈希不匹配,则客户端可以向服务器请求文件。

您可以根据需要执行此操作……或者让服务器发送包含所有文件及其哈希值的清单,并在前面执行此操作,并带有进度条。

您也可以考虑使用二进制差异解决方案,但这超出了本文的范围。

【讨论】:

非常感谢,您的回答解决了我的问题【参考方案2】:

感谢 theraot 解决了我的问题 我这样做。并且此代码适用于任何项目只需复制和粘贴只需更改端口号

`### clint side
# main clint server code
var network
var port = 9166
var ip = "127.0.0.1"

# create clint server
func _ready():
    network = NetworkedMultiplayerENet.new()
    network.create_client(ip,port)
    get_tree().set_network_peer(network)
    print("server start")
    
    network.connect("connection_failed",self,"_Network_connection_failed")
    network.connect("connection_succeeded",self,"_Network_connection_succeeded")
    
# sinal shot when you connect to server
func _Network_connection_succeeded():
    print("connect")
# sinal shot when you disconnect to server
func _Network_connection_failed():
    print("disconnect")

# must be called in the game for file that you want
func send_object_requast(object):
    rpc_id(1,"send_back_object", object)

# server response to your requast
remote func received_object(informatoin):
    # i dont know have to create new file so i copy existing file
    # if you know help me
    var file = Directory.new()
    file.copy("res://sourse/2d material/white.png","res://sourse/2d material/123.png")
    
    # store file in flie you create
    var object = File.new()
    object.open("res://sourse/2d material/123.png", File.WRITE)
    object.store_buffer(informatoin)
    object.close()
    print("done")`

你应该做服务器项目

`## server side
# main ENet code
var network = NetworkedMultiplayerENet.new()
var port = 9166
var max_player = 100

# create server
func _ready():
    network.create_server(port,max_player)
    get_tree().set_network_peer(network)
    print("main server start")
    network.connect("peer_connected", self,"peer_connected_")
    network.connect("peer_disconnected", self, "peer_disconnected_")

# signal shot when any clint connect
func peer_connected_(player_id):
    print("user " + str(player_id) + "connect")

# signal shot when any clint diconnect
func peer_disconnected_(player_id):
    print("user" + str(player_id)+ "disconnect")


# received and response back to clint
remote func send_back_object(object):
    var plyer_id = get_tree().get_rpc_sender_id()
    var file = File.new()
    # you can choise any file for testing i choise godot icon
    file.open("res://icon.png", File.READ)
    var bytes : PoolByteArray = file.get_buffer(file.get_len())
    file.close()
    rpc_id(plyer_id, "received_object", bytes)`

【讨论】:

我不会说英语,很好,请原谅我 要创建一个新文件,你可以用File.WRITE打开它。如果它不存在,Godot 将创建它。编辑:顺便说一句,您将要写入user:// 路径。顺便说一句,我在MultiplayerAPI 周围写下了我的答案,以便能够使用send_bytes,因为您想发送PoolByteArray。如果您使用 rpc,则不限于发送PoolByteArray。我相信您应该能够load 资源并发送它。否则,您可以使用var2bytesbytes2var 或类似的(例如var2strstr2var)。

以上是关于如何使用带有脚本的 godot fbx 导入器的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Unity 导出带有纹理的 fbx?

如何在unity3d发布好的程序中导入外部文件?

如何将搅拌机文件导出到 fbx 并将其导入统一,使其外观和工作方式相同?

如何使用 FBX SDK 在 fbx 文件中加载嵌入的纹理? [关闭]

Unity3D 4 - 导入的动画 fbx 模型干扰物理

Maya:如何使用 python 导入 fbx?