From c5097f91be570773f35d7fcb6b6086e613718a77 Mon Sep 17 00:00:00 2001 From: tzdwindows 7 <3076584115@qq.com> Date: Sat, 1 Nov 2025 19:17:03 +0800 Subject: [PATCH] =?UTF-8?q?feat(render):=20=E5=AE=9E=E7=8E=B0=20liquify=20?= =?UTF-8?q?overlay=20=E6=98=BE=E7=A4=BA=E6=8E=A7=E5=88=B6=E4=B8=8E?= =?UTF-8?q?=E9=A1=B6=E7=82=B9=E5=90=8C=E6=AD=A5=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 Mesh2D 中新增 isShowLiquifyOverlay 方法,用于控制 liquify overlay 的显示状态 - 修改 drawLiquifyOverlay 方法,增加对 mesh2D.isShowLiquifyOverlay() 的判断 - 重构 ModelPart 的 setPosition 方法,优化多选和单选状态下的顶点同步逻辑- 新增 syncSecondaryVerticesForPart 方法,实现部件及其子部件的二级顶点同步移动 - 移除 SelectionTool 中冗余的 syncSecondaryVerticesForPart 方法- 优化 SelectionTool 的 resize 操作逻辑,提高代码可读性和性能 - 在 VertexDeformationRander 中增加对 showSecondaryVertices 状态的检查- 完善多选操作时的中心点计算逻辑,提升用户体验 --- .../render/awt/tools/SelectionTool.java | 90 ++++--------------- .../vivid2D/render/model/ModelPart.java | 83 ++++++++++++++--- .../vivid2D/render/model/util/Mesh2D.java | 4 + .../util/tools/LiquifyTargetPartRander.java | 2 +- .../util/tools/VertexDeformationRander.java | 2 +- 5 files changed, 97 insertions(+), 84 deletions(-) diff --git a/src/main/java/com/chuangzhou/vivid2D/render/awt/tools/SelectionTool.java b/src/main/java/com/chuangzhou/vivid2D/render/awt/tools/SelectionTool.java index 6fd719b..db513a2 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/awt/tools/SelectionTool.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/awt/tools/SelectionTool.java @@ -324,9 +324,6 @@ public class SelectionTool extends Tool { for (ModelPart part : selectedParts) { Vector2f pos = part.getPosition(); part.setPosition(pos.x + deltaX, pos.y + deltaY); - - // 同步移动该部件下的所有网格的二级顶点 - syncSecondaryVerticesForPart(part, deltaX, deltaY); } // 更新拖拽起始位置 @@ -395,16 +392,12 @@ public class SelectionTool extends Tool { private void handleResizeDrag(float modelX, float modelY) { if (lastSelectedMesh == null) return; - ModelPart selectedPart = findPartByMesh(lastSelectedMesh); - if (selectedPart == null) return; - float deltaX = modelX - dragStartX; float deltaY = modelY - dragStartY; float relScaleX = 1.0f; float relScaleY = 1.0f; - // 根据拖拽模式计算相对缩放比例 switch (currentDragMode) { case RESIZE_LEFT: relScaleX = (resizeStartWidth - deltaX) / Math.max(1e-6f, resizeStartWidth); @@ -436,92 +429,47 @@ public class SelectionTool extends Tool { break; } - // 如果按住Shift键,等比例缩放 + // Shift 键等比例缩放 if (renderPanel.getKeyboardManager().getIsShiftPressed() || shiftDuringDrag) { float uniform = (relScaleX + relScaleY) * 0.5f; relScaleX = uniform; relScaleY = uniform; } - // 应用缩放到所有选中的部件 List selectedParts = getSelectedParts(); + Vector2f center = getMultiSelectionCenter(); // 整个多选的中心点 + for (ModelPart part : selectedParts) { Vector2f currentScale = part.getScale(); - part.setScale(currentScale.x * relScaleX, currentScale.y * relScaleY); + float newScaleX = currentScale.x * relScaleX; + float newScaleY = currentScale.y * relScaleY; - // 同步缩放该部件下的所有网格的二级顶点 - //syncSecondaryVerticesScaleForPart(part, relScaleX, relScaleY); + // 更新部件自身缩放 + part.setScale(newScaleX, newScaleY); } - // 更新拖拽起始位置和初始尺寸 + + // 更新拖拽起始点和尺寸 dragStartX = modelX; dragStartY = modelY; resizeStartWidth *= relScaleX; resizeStartHeight *= relScaleY; } - /** - * 同步部件下所有网格的二级顶点位置 - */ - private void syncSecondaryVerticesForPart(ModelPart part, float deltaX, float deltaY) { - if (part == null) return; + private Vector2f getMultiSelectionCenter() { + List selectedParts = getSelectedParts(); + if (selectedParts.isEmpty()) return new Vector2f(0, 0); - List meshes = part.getMeshes(); - if (meshes == null) return; + float sumX = 0f; + float sumY = 0f; - for (Mesh2D mesh : meshes) { - if (mesh != null && mesh.isVisible() && mesh.getSecondaryVertexCount() > 0) { - - List secondaryVertices = mesh.getSecondaryVertices(); - if (secondaryVertices != null) { - - // 遍历所有顶点,逐个调用 moveSecondaryVertex - for (SecondaryVertex vertex : secondaryVertices) { - - // 【修正 1:避免双重平移和状态冲突】 - // 仅对未锁定/未固定的顶点执行局部坐标平移。 - // 锁定的顶点不应被工具的同步逻辑移动,它们应该随 ModelPart 的世界变换移动。 - if (!vertex.isLocked() && !vertex.isPinned()) { - - // 计算顶点的新局部坐标 (position + delta) - float newX = vertex.getPosition().x + deltaX; - float newY = vertex.getPosition().y + deltaY; - - // 使用 moveSecondaryVertex 方法 - mesh.moveSecondaryVertex(vertex, newX, newY); - // 注意:mesh.moveSecondaryVertex 内部会触发形变计算和 markDirty - } - } - } - } - } - part.setPosition(part.getPosition()); - - // 递归处理子部件 - for (ModelPart child : part.getChildren()) { - syncSecondaryVerticesForPart(child, deltaX, deltaY); - } - } - - /** - * 同步部件下所有网格的二级顶点缩放 - */ - private void syncSecondaryVerticesScaleForPart(ModelPart part, float scaleX, float scaleY) { - if (part == null) return; - - List meshes = part.getMeshes(); - if (meshes == null) return; - - for (Mesh2D mesh : meshes) { - if (mesh != null && mesh.getSecondaryVertexCount() > 0) { - mesh.syncSecondaryVerticesToBounds(); - } + for (ModelPart part : selectedParts) { + Vector2f pos = part.getPosition(); + sumX += pos.x; + sumY += pos.y; } - // 递归处理子部件 - for (ModelPart child : part.getChildren()) { - syncSecondaryVerticesScaleForPart(child, scaleX, scaleY); - } + return new Vector2f(sumX / selectedParts.size(), sumY / selectedParts.size()); } /** diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/ModelPart.java b/src/main/java/com/chuangzhou/vivid2D/render/model/ModelPart.java index 794db77..52084e5 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/ModelPart.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/ModelPart.java @@ -1549,7 +1549,9 @@ public class ModelPart { public void setPosition(float x, float y) { // 防止递归调用 if (inMultiSelectionOperation) { - // 直接执行单选择辑,避免递归 + float deltaX = x - position.x; + float deltaY = y - position.y; + position.set(x, y); markTransformDirty(); updateLocalTransform(); @@ -1560,28 +1562,42 @@ public class ModelPart { mesh.setPivot(worldPivot.x, worldPivot.y); } - updateMeshVertices(); + syncSecondaryVerticesForPart(this, deltaX, deltaY); triggerEvent("position"); return; } - // 如果是多选状态下的移动,使用多选移动方法 - if (isInMultiSelection() && !getSelectedMeshes().isEmpty()) { - Vector2f currentPos = getPosition(); - float dx = x - currentPos.x; - float dy = y - currentPos.y; + float oldX = position.x; + float oldY = position.y; + + // 多选状态下移动 + if (isInMultiSelection() && !getSelectedMeshes().isEmpty()) { + float dx = x - oldX; + float dy = y - oldY; - // 设置标志防止递归 inMultiSelectionOperation = true; try { - moveSelectedMeshes(dx, dy); + moveSelectedMeshes(dx, dy); // 这里会调用 setPosition,但被 inMultiSelectionOperation 拦截 } finally { inMultiSelectionOperation = false; } + + // 更新自身位置 + position.set(x, y); + markTransformDirty(); + updateLocalTransform(); + recomputeWorldTransformRecursive(); + + for (Mesh2D mesh : meshes) { + Vector2f worldPivot = Matrix3fUtils.transformPoint(worldTransform, mesh.getOriginalPivot()); + mesh.setPivot(worldPivot.x, worldPivot.y); + } + + triggerEvent("position"); return; } - // 原有单选择辑 + // 单选逻辑 position.set(x, y); markTransformDirty(); updateLocalTransform(); @@ -1592,12 +1608,57 @@ public class ModelPart { mesh.setPivot(worldPivot.x, worldPivot.y); } + float deltaX = x - oldX; + float deltaY = y - oldY; - updateMeshVertices(); + syncSecondaryVerticesForPart(this, deltaX, deltaY); triggerEvent("position"); } + /** + * 同步部件下所有网格的二级顶点位置 + */ + private void syncSecondaryVerticesForPart(ModelPart part, float deltaX, float deltaY) { + if (part == null) return; + + List meshes = part.getMeshes(); + if (meshes == null) return; + + for (Mesh2D mesh : meshes) { + if (mesh != null && mesh.isVisible() && mesh.getSecondaryVertexCount() > 0) { + + List secondaryVertices = mesh.getSecondaryVertices(); + if (secondaryVertices != null) { + + // 遍历所有顶点,逐个调用 moveSecondaryVertex + for (SecondaryVertex vertex : secondaryVertices) { + + // 【修正 1:避免双重平移和状态冲突】 + // 仅对未锁定/未固定的顶点执行局部坐标平移。 + // 锁定的顶点不应被工具的同步逻辑移动,它们应该随 ModelPart 的世界变换移动。 + if (!vertex.isLocked() && !vertex.isPinned()) { + + // 计算顶点的新局部坐标 (position + delta) + float newX = vertex.getPosition().x + deltaX; + float newY = vertex.getPosition().y + deltaY; + + // 使用 moveSecondaryVertex 方法 + mesh.moveSecondaryVertex(vertex, newX, newY); + // 注意:mesh.moveSecondaryVertex 内部会触发形变计算和 markDirty + } + } + } + } + } + part.setPosition(part.getPosition()); + + // 递归处理子部件 + for (ModelPart child : part.getChildren()) { + syncSecondaryVerticesForPart(child, deltaX, deltaY); + } + } + /** * 更新所有网格的顶点位置以反映当前变换 */ diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/util/Mesh2D.java b/src/main/java/com/chuangzhou/vivid2D/render/model/util/Mesh2D.java index 7a94ae0..4122f2a 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/util/Mesh2D.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/util/Mesh2D.java @@ -657,6 +657,10 @@ public class Mesh2D { markDirty(); } + public boolean isShowLiquifyOverlay() { + return showLiquifyOverlay; + } + /** * 设置中心点 */ diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/util/tools/LiquifyTargetPartRander.java b/src/main/java/com/chuangzhou/vivid2D/render/model/util/tools/LiquifyTargetPartRander.java index 052e41b..4d14cc7 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/util/tools/LiquifyTargetPartRander.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/util/tools/LiquifyTargetPartRander.java @@ -53,7 +53,7 @@ public class LiquifyTargetPartRander extends RanderTools { * 主渲染入口。收集文本命令到 pendingTexts,绘制完成后 popState,再把文本绘制出来(外部渲染) */ private void drawLiquifyOverlay(Mesh2D mesh2D, Matrix3f modelMatrix) { - if (!isAlgorithmEnabled("showLiquifyOverlay")) return; + if (!isAlgorithmEnabled("showLiquifyOverlay") || !mesh2D.isShowLiquifyOverlay()) return; List pendingTexts = new ArrayList<>(); diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/util/tools/VertexDeformationRander.java b/src/main/java/com/chuangzhou/vivid2D/render/model/util/tools/VertexDeformationRander.java index 922f758..ca7f478 100644 --- a/src/main/java/com/chuangzhou/vivid2D/render/model/util/tools/VertexDeformationRander.java +++ b/src/main/java/com/chuangzhou/vivid2D/render/model/util/tools/VertexDeformationRander.java @@ -41,7 +41,7 @@ public class VertexDeformationRander extends RanderTools { * 绘制二级顶点(现代化样式) */ private void drawSecondaryVertices(Mesh2D mesh2D, Matrix3f modelMatrix) { - if (!isAlgorithmEnabled("showSecondaryVertices") || mesh2D.getSecondaryVertices().isEmpty()) return; + if (!isAlgorithmEnabled("showSecondaryVertices") || mesh2D.getSecondaryVertices().isEmpty() || !mesh2D.isShowSecondaryVertices()) return; RenderSystem.pushState(); try {