per-mesh 引用:MeshRendererComponent.meshIndex(-1=整模型)贯穿渲染收集/物理 Mesh 碰撞(自动跟随)/场景序列化(缺省键向前兼容)/Inspector mesh 下拉
This commit is contained in:
@@ -203,6 +203,10 @@ namespace Engine::ECS {
|
||||
struct MeshRendererComponent {
|
||||
ModelRef model;
|
||||
bool active = true; // 禁用 = 渲染/拾取跳过(Unity enabled / UE SetActive)
|
||||
// 单 mesh 子引用:-1 = 整模型全部;N = 只画第 N 个
|
||||
//(GetMeshes 下标)。物理 Mesh 碰撞体自动跟随(BuildMeshShape
|
||||
// 读本组件)。序列化缺省键 = -1 向前兼容
|
||||
int meshIndex = -1;
|
||||
std::unordered_map<u32, std::string> materialOverrides;
|
||||
};
|
||||
|
||||
@@ -222,6 +226,11 @@ namespace Engine::ECS {
|
||||
bool playing = true;
|
||||
bool loop = true;
|
||||
f32 speed = 1.0f;
|
||||
// 根运动开关(Unity Animator "Apply Root Motion" 同语义):
|
||||
// true = 保留根节点位移轨道(跑动 clip 自带位移会漂出锚点);
|
||||
// false = 原地播放(丢弃动画子树根节点位移,旋转保留)——
|
||||
// 位移归脚本/物理驱动的角色(CharacterController 等)用 false
|
||||
bool applyRootMotion = true;
|
||||
|
||||
// ---- 播放头 / crossfade(瞬态,不落盘——重启从 0 重播)----
|
||||
f32 time = 0.0f; // 当前 clip 播放头(秒,wrap 由消费端处理)
|
||||
|
||||
@@ -767,8 +767,14 @@ namespace Engine {
|
||||
// 动态/运动体 → ConvexHull(MeshShape 三角网格太贵,Jolt 不允许动)
|
||||
if (rb.type != ECS::RigidBodyComponent::BodyType::Static) {
|
||||
JPH::ConvexHullShapeSettings cs;
|
||||
for (const auto &mesh: model->GetMeshes()) {
|
||||
for (const auto &p: mesh->GetCpuPositions()) {
|
||||
const auto &meshes = model->GetMeshes();
|
||||
for (size_t mi = 0; mi < meshes.size(); ++mi) {
|
||||
// 单 mesh 子引用:碰撞只取渲染可见的同一 mesh(语义跟随)
|
||||
if (mc->meshIndex >= 0 &&
|
||||
static_cast<int>(mi) != mc->meshIndex) {
|
||||
continue;
|
||||
}
|
||||
for (const auto &p: meshes[mi]->GetCpuPositions()) {
|
||||
cs.mPoints.emplace_back(p.x * s.x, p.y * s.y, p.z * s.z);
|
||||
}
|
||||
}
|
||||
@@ -788,9 +794,15 @@ namespace Engine {
|
||||
JPH::VertexList verts;
|
||||
JPH::IndexedTriangleList tris;
|
||||
u32 base = 0;
|
||||
for (const auto &mesh: model->GetMeshes()) {
|
||||
const auto &pos = mesh->GetCpuPositions();
|
||||
const auto &idx = mesh->GetCpuIndices();
|
||||
const auto &meshes = model->GetMeshes();
|
||||
for (size_t mi = 0; mi < meshes.size(); ++mi) {
|
||||
// 单 mesh 子引用:碰撞只取渲染可见的同一 mesh(语义跟随)
|
||||
if (mc->meshIndex >= 0 &&
|
||||
static_cast<int>(mi) != mc->meshIndex) {
|
||||
continue;
|
||||
}
|
||||
const auto &pos = meshes[mi]->GetCpuPositions();
|
||||
const auto &idx = meshes[mi]->GetCpuIndices();
|
||||
verts.reserve(verts.size() + pos.size());
|
||||
for (const auto &p: pos) {
|
||||
verts.push_back(JPH::Float3(p.x * s.x, p.y * s.y, p.z * s.z));
|
||||
|
||||
@@ -757,6 +757,12 @@ namespace Engine
|
||||
|
||||
const auto& meshes = model->GetMeshes();
|
||||
for (size_t meshIdx = 0; meshIdx < meshes.size(); ++meshIdx) {
|
||||
// 单 mesh 子引用:只收集指派的那一个(覆盖表/物理
|
||||
// 均按原模型下标,语义不变)
|
||||
if (mr.meshIndex >= 0 &&
|
||||
static_cast<int>(meshIdx) != mr.meshIndex) {
|
||||
continue;
|
||||
}
|
||||
auto& mesh = meshes[meshIdx];
|
||||
const auto& bounds = mesh->GetBounds();
|
||||
const glm::vec3 worldCenter =
|
||||
|
||||
@@ -312,6 +312,11 @@ namespace Engine::Serialization {
|
||||
out << YAML::Key << "Path" << YAML::Value << path;
|
||||
out << YAML::EndMap; // Model(flow)
|
||||
out << YAML::Key << "Active" << YAML::Value << mr->active;
|
||||
// 单 mesh 子引用(-1 = 整模型,缺省键向前兼容)
|
||||
if (mr->meshIndex >= 0) {
|
||||
out << YAML::Key << "MeshIndex"
|
||||
<< YAML::Value << mr->meshIndex;
|
||||
}
|
||||
// 材质覆盖表(UE Material Slot):seq of {Slot,Guid,Path}
|
||||
if (!mr->materialOverrides.empty()) {
|
||||
out << YAML::Key << "MaterialOverrides"
|
||||
@@ -609,6 +614,7 @@ namespace Engine::Serialization {
|
||||
handle.GetComponent<ECS::MeshRendererComponent>();
|
||||
mrComp.active =
|
||||
n["Active"].as<bool>(true); // 缺省 true 向前兼容
|
||||
mrComp.meshIndex = n["MeshIndex"].as<int>(-1);
|
||||
// 材质覆盖表:逐项解析(guid 反查 → path 兜底)
|
||||
// 并预载;加载失败保留路径(收集期回退内建材质)
|
||||
if (const YAML::Node ovs = n["MaterialOverrides"]) {
|
||||
|
||||
Reference in New Issue
Block a user