CARLA .co n CARLA 原生车库里的那几十辆车,对日常调试感知算法或许够用,可一旦你想验证快递小车、园区清扫车,或者自己设计的异形无人艇,就会发现“官方套餐”根本不够用。更糟的是,同一辆车跑在 0.9.14 与 0.9.15 里,车身包围盒还可能悄悄漂移——自定义模型成了算法回归测试里绕不过去的刚需。下面把我在 Blender → FBX → CARLA 这条“血泪之路”踩过的坑,整理成一份可直接照抄的 Cookbook,帮你把模型从硬盘搬进仿真世界,还能让它跑起来、撞上去、换皮肤,一条龙到位。
1. 为什么一定要自己导模型?
CARLA 自带的 3D 库虽然看着丰富,却有三道紧箍咒:
- 版权限制:官方模型多数来自 Epic 的免费素材,改完不能商用
- 拓扑固定:LOD 组已经打包装进
.pak,想拆成“可行驶区域/不可行驶区域”做语义分割,只能自己重拓扑 - 物理参数硬编码:质量、质心、轮胎曲线写死在 JSON,换套轮胎就要改源码
把自家 CAD 数据灌进 CARLA,就能在仿真里 1:1 复现真车质量、传感器布局,甚至把轮胎磨损曲线也带进来,闭环验证控制算法——这一步省不得。
2. 技术方案三步走
2.1 Blender 建模规范:别让“米”变成“厘米”
- 单位:Scene Properties → Units → Length 选Metric,Scale 1 BU = 1 m
- 坐标系:CARLA 是 Z-up、Y-forward 朝前,所以
- 前视图(+Y)对准车头
- 左视图(+X)对准右侧车门
- 俯视图(+Z)向上
- 材质命名:用
CarPaint_0、Window_1、Wheel_2这种“语义_序号”格式,方便后面 Python 批量替换 - UV 展开:所有贴图共用 0-1 空间,重叠部分手动移出,否则 CARLA 会随机采样导致“花脸”
- 原点设置:车身原点放在后轴中心地面处,这样导入后
vehicle.get_location()直接就是“后轴中心”,与车辆动力学公式对齐
2.2 FBX 导出参数:把“旋转”扼杀在摇篮里
Blender 导出面板默认会带 90° 旋转,CARLA 认不出。用官方自带io_scene_fbx的 Python 接口最稳:
import bpy import os src = bpy.context.scene.objects fbx_path = r"/tmp/MyCar.fbx" # 选中所有网格 bpy.ops.object.select_all(action='DESELECT') for obj in src: if obj.type == 'MESH': obj.select_set(True) bpy.ops.export_scene.fbx( filepath=fbx_path, use_selection=True, apply_unit_scale=True, # 关键:把 Blender 单位强制转成米 apply_scale_options='FBX_SCALE_ALL', axis_forward='Y', # 车头朝 +Y axis_up='Z', # 车顶朝 +Z bake_space_transform=True, # 把旋转冻结掉 mesh_smooth_type='OFF', # CARLA 认不出“面平滑组”,关掉 add_leaf_bones=False, path_mode='COPY', # 贴图打包 embed_textures=True, )导出后记得用 Autodesk FBX Review 打开,确认车头朝前、没有 90° 歪头,再进入下一步。
2.3 CARLA 材质系统:Diffuse / Specular / Normal 三板斧
CARLA 的渲染管线是 Deferred+PBR,贴图必须按命名后缀才能被识别:
_diff/_diffuse→ BaseColor_spec/_specular→ Specular_n/_normal→ Normal
如果 Blender 里用了 ORM 贴图(R=AO, G=Rough, B=Metal),需要拆图:
import cv2 import numpy as np orm = cv2.imread('CarPaint_ORM.png') cv2.imwrite('CarPaint_metal.png', orm[:,:,2]) # B 通道 → Metallic cv2.imwrite('CarPaint_rough.png', orm[:,:,1]) # G 通道 → Roughness把拆完的图跟 FBX 放同目录,CARLA 在导入时会自动匹配。
3. 完整导入脚本:让模型在世界里“活”起来
下面脚本一次性完成“蓝图注册 + 碰撞体 + 动态换肤”,存成spawn_my_car.py,在 CARLA PythonAPI 里直接跑:
#!/usr/bin/env python3 # -*- coding:utf-8 -*- import carla import os import random client = carla.Client('localhost', 2000) world = client.get_world() bp_lib = world.get_blueprint_library() # 1. 把 FBX 烤成 .uasset(需先放 Import 文件夹) # 这里假设你已经用 Unreal 编辑器的 Import 菜单导了一遍, # 得到路径 /Game/Vehicles/MyCar/MyCar.fbx my_car_bp = bp_lib.filter('vehicle.*')[0] # 先拿模板 my_car_bp.set_attribute('base_type', 'MyCar') # 自定义标记 # 2. 生成碰撞体(简化为 Box,真车可用 Mesh Collider) spawn_point = random.choice(world.get_map().get_spawn_points()) vehicle = world.spawn_actor(my_car_bp, spawn_point) # 3. 动态换皮肤:根据车速换 Diffuse def change_skin(speed_kmh): if speed_kmh < 30: skin = 'CarPaint_diff' # 城市绿 else: skin = 'CarPaint_diff_race' # 赛道拉花 vehicle.set_light_state(carla.VehicleLightState.NONE) # 通过 Material Instance 换贴图(略,需 UE 侧先建 Instance) # 4. 物理参数覆盖(质量单位 kg) physics = vehicle.get_physics_control() physics.mass = 1450.0 physics.center_of_mass = carla.Vector3D(0, 0, 0.35) vehicle.apply_physics_control(physics)跑通后,在 UE 编辑器里能看到MyCar蓝图已出现在 Vehicles 目录,拖进场景就能开。
4. 避坑指南:把“血泪”变“经验”
比例尺不一致 → 车重 1.45 kg,一碰就飞
解决:Blender 导出时一定勾Apply Unit,并在 CARLA 侧用physics.mass再写一次透明车窗变黑 → CARLA 默认 Blend 模式 Opaque
解决:在 UE 材质里把 Blend Mode 改Translucent,并给Opacity Clip值 0.45高模卡成 PPT → 一帧 5 ms
解决:- 做三级 LOD:50 k / 10 k / 2 k 三角面
- 车轮单独导出,勾选Use Complex Collision as Simple
- 关闭 Distance Field,换 Forward Shading,帧率立涨 30 %
5. 把 OBJ 也搬进来?试试模板仓库
如果你手里只有.obj,流程完全一样:
- Blender 导入 → 按第 2 节规范整理 → 走同一条 FBX 导出 → 脚本 spawn
我放了一份 GitHub 模板,含示例车、拆分贴图脚本、以及上面spawn_my_car.py,clone 即可用:
https://github.com/yourname/carla-custom-vehicle-template
6. 写在最后
把自家模型搬进 CARLA 看似只是“导个文件”,实则是把“算法—车辆—场景”三环真正闭合。走完上面流程,你不仅能在仿真里跑自己的车,还能顺手把质量、惯量、轮胎曲线这些“隐藏参数”也带进来,让控制算法在上线前就完成一次“真车级”回归。如果你也想把语音交互能力搬进数字座舱,可以顺手试试从0打造个人豆包实时通话AI动手实验——同样是从零配置到跑通 Demo,一条命令就能在浏览器里跟“数字副驾”唠嗑。仿真 + 语音,两条线都通了,距离“全栈自动驾驶 Demo”就又近了一步。祝导入顺利,我们仿真赛道见!