Implement the apply scale to object functionality (#1363)
This commit is contained in:
committed by
GitHub
parent
fe210e1d20
commit
3d64ae533a
+134
-1
@@ -416,6 +416,138 @@ void TransformWindow::Create(EditorComponent* _editor)
|
||||
});
|
||||
AddWidget(&resetRotationButton);
|
||||
|
||||
applyScaleToObjectButton.Create("Apply Scale to Object");
|
||||
applyScaleToObjectButton.SetTooltip("Recomputes the vertex positions of child object meshes, morph target positions, and armature bones to apply the current transform scale");
|
||||
applyScaleToObjectButton.SetSize(XMFLOAT2(wid + hei + 1, hei));
|
||||
applyScaleToObjectButton.OnClick([=](wi::gui::EventArgs args) {
|
||||
Scene& scene = editor->GetCurrentScene();
|
||||
TransformComponent* transform = scene.transforms.GetComponent(entity);
|
||||
if (transform == nullptr)
|
||||
return;
|
||||
|
||||
const XMFLOAT3& scale = transform->scale_local;
|
||||
if (scale.x == 1.0f && scale.y == 1.0f && scale.z == 1.0f)
|
||||
return;
|
||||
|
||||
wi::Archive& archive = editor->AdvanceHistory();
|
||||
archive << EditorComponent::HISTORYOP_COMPONENT_DATA;
|
||||
editor->RecordEntity(archive, entity);
|
||||
|
||||
wi::vector<Entity> entities_to_process;
|
||||
entities_to_process.push_back(entity);
|
||||
scene.GatherChildren(entity, entities_to_process);
|
||||
|
||||
wi::unordered_set<Entity> processed_meshes;
|
||||
wi::unordered_set<Entity> processed_armatures;
|
||||
|
||||
for (Entity e : entities_to_process)
|
||||
{
|
||||
// Process ObjectComponent meshes
|
||||
ObjectComponent* object = scene.objects.GetComponent(e);
|
||||
if (object != nullptr && object->meshID != INVALID_ENTITY)
|
||||
{
|
||||
if (processed_meshes.count(object->meshID) == 0)
|
||||
{
|
||||
processed_meshes.insert(object->meshID);
|
||||
|
||||
MeshComponent* mesh = scene.meshes.GetComponent(object->meshID);
|
||||
if (mesh != nullptr)
|
||||
{
|
||||
editor->RecordEntity(archive, object->meshID);
|
||||
|
||||
// Apply scale to all vertex positions
|
||||
for (XMFLOAT3& pos : mesh->vertex_positions)
|
||||
{
|
||||
pos.x *= scale.x;
|
||||
pos.y *= scale.y;
|
||||
pos.z *= scale.z;
|
||||
}
|
||||
|
||||
// Apply scale to morph target positions
|
||||
for (MeshComponent::MorphTarget& morph : mesh->morph_targets)
|
||||
{
|
||||
for (XMFLOAT3& pos : morph.vertex_positions)
|
||||
{
|
||||
pos.x *= scale.x;
|
||||
pos.y *= scale.y;
|
||||
pos.z *= scale.z;
|
||||
}
|
||||
}
|
||||
|
||||
// Process the armature associated with this mesh
|
||||
if (mesh->armatureID != INVALID_ENTITY && processed_armatures.count(mesh->armatureID) == 0)
|
||||
{
|
||||
processed_armatures.insert(mesh->armatureID);
|
||||
|
||||
ArmatureComponent* armature = scene.armatures.GetComponent(mesh->armatureID);
|
||||
if (armature != nullptr)
|
||||
{
|
||||
editor->RecordEntity(archive, mesh->armatureID);
|
||||
|
||||
// Apply scale to inverse bind matrices
|
||||
for (XMFLOAT4X4& bind : armature->inverseBindMatrices)
|
||||
{
|
||||
XMVECTOR V_S, V_R, V_T;
|
||||
XMMatrixDecompose(&V_S, &V_R, &V_T, XMLoadFloat4x4(&bind));
|
||||
XMFLOAT3 pos, bindScale;
|
||||
XMFLOAT4 rot;
|
||||
XMStoreFloat3(&bindScale, V_S);
|
||||
XMStoreFloat3(&pos, V_T);
|
||||
XMStoreFloat4(&rot, V_R);
|
||||
|
||||
// Scale the translation component
|
||||
pos.x *= scale.x;
|
||||
pos.y *= scale.y;
|
||||
pos.z *= scale.z;
|
||||
|
||||
XMMATRIX newBind =
|
||||
XMMatrixScalingFromVector(XMLoadFloat3(&bindScale)) *
|
||||
XMMatrixRotationQuaternion(XMLoadFloat4(&rot)) *
|
||||
XMMatrixTranslationFromVector(XMLoadFloat3(&pos));
|
||||
XMStoreFloat4x4(&bind, newBind);
|
||||
}
|
||||
|
||||
// Apply scale to bone transforms
|
||||
for (Entity boneEntity : armature->boneCollection)
|
||||
{
|
||||
TransformComponent* boneTransform = scene.transforms.GetComponent(boneEntity);
|
||||
if (boneTransform != nullptr)
|
||||
{
|
||||
editor->RecordEntity(archive, boneEntity);
|
||||
|
||||
boneTransform->translation_local.x *= scale.x;
|
||||
boneTransform->translation_local.y *= scale.y;
|
||||
boneTransform->translation_local.z *= scale.z;
|
||||
boneTransform->SetDirty();
|
||||
|
||||
editor->RecordEntity(archive, boneEntity);
|
||||
}
|
||||
}
|
||||
|
||||
editor->RecordEntity(archive, mesh->armatureID);
|
||||
}
|
||||
}
|
||||
|
||||
// Recreate render data for the modified mesh
|
||||
mesh->CreateRenderData();
|
||||
if (!mesh->BLASes.empty())
|
||||
{
|
||||
mesh->CreateRaytracingRenderData();
|
||||
}
|
||||
|
||||
editor->RecordEntity(archive, object->meshID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
transform->scale_local = XMFLOAT3(1, 1, 1);
|
||||
transform->SetDirty();
|
||||
|
||||
editor->RecordEntity(archive, entity);
|
||||
});
|
||||
AddWidget(&applyScaleToObjectButton);
|
||||
|
||||
|
||||
SetMinimized(true);
|
||||
SetVisible(false);
|
||||
@@ -507,10 +639,11 @@ void TransformWindow::ResizeLayout()
|
||||
ryInput.SetPos(XMFLOAT2(rzInput.GetPos().x - ryInput.GetSize().x - layout.padding, rzInput.GetPos().y));
|
||||
rxInput.SetPos(XMFLOAT2(ryInput.GetPos().x - rxInput.GetSize().x - layout.padding, ryInput.GetPos().y));
|
||||
|
||||
layout.add_fullwidth(applyScaleToObjectButton);
|
||||
|
||||
layout.jump();
|
||||
|
||||
layout.add_right(snapScaleInput);
|
||||
layout.add_right(snapRotateInput);
|
||||
layout.add_right(snapTranslateInput);
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user