From fe4142902cfaac133cf3b77c5242fc618d4d3de9 Mon Sep 17 00:00:00 2001
From: tzdwindows 7 <3076584115@qq.com>
Date: Fri, 21 Nov 2025 16:46:37 +0800
Subject: [PATCH] =?UTF-8?q?feat(render):=20=E5=AE=9E=E7=8E=B0=E5=8A=A8?=
=?UTF-8?q?=E6=80=81=E7=BC=A9=E6=94=BE=E6=94=AF=E6=8C=81=E4=B8=8E=E6=96=87?=
=?UTF-8?q?=E6=9C=AC=E6=B8=B2=E6=9F=93=E4=BC=98=E5=8C=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 为 BoundingBox 类添加获取中心点坐标的便捷方法
- 重构 Mesh2D 悬停提示框绘制逻辑,支持基于摄像机缩放的动态尺寸计算
- 在 ModelRender 中新增带缩放参数的文本渲染方法
- 重写 MultiSelectionBoxRenderer 以适配动态缩放,统一使用像素单位配置
- 优化 ParametersManagement 日志记录方式
- 修复 TextRenderer 字体颜色传递问题
- 更新 TextShader 着色器代码以兼容新的渲染管线和透明度处理
---
.../vivid2D/render/ModelRender.java | 26 +-
.../render/MultiSelectionBoxRenderer.java | 348 ++++++++----------
.../vivid2D/render/TextRenderer.java | 1 +
.../awt/manager/ParametersManagement.java | 6 +-
.../vivid2D/render/model/Mesh2D.java | 72 ++--
.../render/model/util/BoundingBox.java | 16 +
.../systems/sources/def/TextShader.java | 26 +-
7 files changed, 234 insertions(+), 261 deletions(-)
diff --git a/src/main/java/com/chuangzhou/vivid2D/render/ModelRender.java b/src/main/java/com/chuangzhou/vivid2D/render/ModelRender.java
index df28d05..c91c71b 100644
--- a/src/main/java/com/chuangzhou/vivid2D/render/ModelRender.java
+++ b/src/main/java/com/chuangzhou/vivid2D/render/ModelRender.java
@@ -52,7 +52,7 @@ import java.util.concurrent.atomic.AtomicInteger;
*
{@link com.chuangzhou.vivid2D.test.ModelTest2} - 进阶模型测试
*
*
- * @author tzdwindows
+ * @author tzdwindows 7
* @version 1.2
* @since 2025-10-13
*/
@@ -982,38 +982,23 @@ public final class ModelRender {
if (shaderList == null || shaderList.isEmpty()) {
return;
}
-
- // 保存当前绑定的着色器程序
int currentProgram = GL11.glGetInteger(GL20.GL_CURRENT_PROGRAM);
-
try {
for (CompleteShader shader : shaderList) {
- // 跳过默认着色器
if (shader.isDefaultShader()) {
continue;
}
-
try {
- // 获取着色器程序
ShaderProgram program = ShaderManagement.getShaderProgram(shader.getShaderName());
if (program == null || program.programId == 0) {
continue;
}
-
program.use();
-
- // 只设置顶点坐标相关的uniform
setUniformMatrix3(program, "uProjectionMatrix", projection);
setUniformMatrix3(program, "uViewMatrix", view);
-
- // 设置基础模型矩阵为单位矩阵
setUniformMatrix3(program, "uModelMatrix", new Matrix3f().identity());
-
- // 设置摄像机Z轴位置
setUniformFloatInternal(program, "uCameraZ", camera.getZPosition());
-
RenderSystem.checkGLError("setupNonDefaultShaders_" + shader.getShaderName());
-
} catch (Exception e) {
logger.warn("Failed to setup non-default shader: {}", shader.getShaderName(), e);
}
@@ -1353,6 +1338,15 @@ public final class ModelRender {
defaultTextRenderer.renderText(text, px, py, color);
}
+ public static void renderText(String text, float x, float y, Vector4f color, float scale) {
+ if (!initialized || defaultTextRenderer == null) return;
+ RenderSystem.assertOnRenderThread();
+ Vector2f offset = getCameraOffset();
+ float px = x - offset.x;
+ float py = y - offset.y;
+ defaultTextRenderer.renderText(text, px, py, color, scale);
+ }
+
/**
* 获取默认摄像机与当前摄像机之间的偏移量
*
diff --git a/src/main/java/com/chuangzhou/vivid2D/render/MultiSelectionBoxRenderer.java b/src/main/java/com/chuangzhou/vivid2D/render/MultiSelectionBoxRenderer.java
index f367d55..ba417e2 100644
--- a/src/main/java/com/chuangzhou/vivid2D/render/MultiSelectionBoxRenderer.java
+++ b/src/main/java/com/chuangzhou/vivid2D/render/MultiSelectionBoxRenderer.java
@@ -9,100 +9,105 @@ import org.joml.Vector4f;
import org.lwjgl.opengl.GL11;
/**
- * MultiSelectionBoxRenderer — 美观版完整实现
+ * MultiSelectionBoxRenderer — 美观版完整实现 (已适配动态缩放 - 边框与手柄)
*
- * 视觉设计目标:
- * - 细腻的三层边框(外发光 -> 主边框 -> 内描边)
- * - 小巧但可见的手柄(角点与边中点略有区分)
- * - 精致的中心点(十字 + 细环)
- * - 虚线用于多选边框
- * - 批处理绘制以减少 Draw Call(尽量在一次 TRIANGLES 调用中绘制多数元素)
- *
- * 注:BufferBuilder 的 vertex(...) 方法签名与项目实现有关,示例中使用 (x,y,z,u) 占位。
+ * 特性:
+ * - 边框、手柄、中心点的大小都会根据视图缩放动态调整,确保在任何缩放级别下都清晰可见。
+ * - 所有元素尽可能在一次 GL_TRIANGLES draw call 中完成,以提高效率。
*/
public class MultiSelectionBoxRenderer {
- // -------------------- 配置常量(可调) --------------------
- // 尺寸
- public static final float DEFAULT_CORNER_SIZE = 8.0f;
+ // -------------------- 配置常量 (世界单位) --------------------
public static final float DEFAULT_DASH_LENGTH = 10.0f;
public static final float DEFAULT_GAP_LENGTH = 6.0f;
- private static final float MAIN_BORDER_THICKNESS = 2.5f;
- // 手柄与中心点尺寸
- private static final float HANDLE_CORNER_SIZE = DEFAULT_CORNER_SIZE;
- private static final float HANDLE_MID_SIZE = 2.8f;
- private static final float CENTER_LINE_THICKNESS = 1.2f;
- private static final float CENTER_RING_RADIUS = 5.0f;
- private static final float CENTER_RING_THICKNESS = 1.2f;
+ // -------------------- 配置常量 (屏幕像素单位) --------------------
+ // 这些值定义了元素在屏幕上看起来应该有多大
+ private static final float PIXEL_MAIN_BORDER_THICKNESS = 2.0f; // <-- 新增:主边框的像素厚度
+ private static final float PIXEL_HANDLE_CORNER_SIZE = 8.0f;
+ private static final float PIXEL_HANDLE_MID_SIZE = 6.0f;
+ private static final float PIXEL_CENTER_LINE_THICKNESS = 1.5f;
+ private static final float PIXEL_CENTER_CROSS_RADIUS = 7.0f;
- // 颜色(更现代、更清爽)
- public static final Vector4f DASHED_BORDER_COLOR = new Vector4f(1.0f, 0.85f, 0.0f, 1.0f); // 黄色虚线
- public static final Vector4f SOLID_BORDER_COLOR_OUTER = new Vector4f(0.0f, 0.85f, 0.95f, 0.12f); // 轻微外发光(弱透明)
- public static final Vector4f SOLID_BORDER_COLOR_MAIN = new Vector4f(0.0f, 0.92f, 0.94f, 1.0f); // 主边框(青)
- public static final Vector4f SOLID_BORDER_COLOR_INNER = new Vector4f(1.0f, 1.0f, 1.0f, 0.9f); // 内描边(接近白)
- public static final Vector4f HANDLE_COLOR = new Vector4f(1.0f, 1.0f, 1.0f, 1.0f); // 手柄白
- public static final Vector4f MULTI_SELECTION_HANDLE_COLOR = new Vector4f(1.0f, 0.9f, 0.0f, 1.0f); // 黄色手柄
- public static final Vector4f CENTER_POINT_COLOR = new Vector4f(1.0f, 0.2f, 0.2f, 1.0f); // 中心点红
-
- // -------------------- 公共绘制 API --------------------
+ // 颜色
+ public static final Vector4f DASHED_BORDER_COLOR = new Vector4f(1.0f, 0.85f, 0.0f, 1.0f);
+ public static final Vector4f SOLID_BORDER_COLOR_MAIN = new Vector4f(0.0f, 0.92f, 0.94f, 1.0f);
+ public static final Vector4f HANDLE_COLOR = new Vector4f(1.0f, 1.0f, 1.0f, 1.0f);
+ public static final Vector4f MULTI_SELECTION_HANDLE_COLOR = new Vector4f(1.0f, 0.9f, 0.0f, 1.0f);
+ public static final Vector4f CENTER_POINT_COLOR = new Vector4f(1.0f, 0.2f, 0.2f, 1.0f);
/**
* 绘制单选的选择框(主入口)
*
* @param bounds 包围盒(世界坐标)
* @param pivot 旋转中心 / 中心点(世界坐标)
+ * @param zoom 当前摄像机的缩放值 (e.g., from ModelRender.getCamera().getZoom())
*/
- public static void drawSelectBox(BoundingBox bounds, Vector2f pivot) {
- if (bounds == null || !bounds.isValid()) return;
+ public static void drawSelectBox(BoundingBox bounds, Vector2f pivot, float zoom) {
+ if (bounds == null || !bounds.isValid() || zoom <= 1e-6f) return;
+
+ // 根据 zoom 计算所有元素在世界坐标下的实际尺寸
+ float worldBorderThickness = PIXEL_MAIN_BORDER_THICKNESS / zoom;
+ float worldCornerSize = PIXEL_HANDLE_CORNER_SIZE / zoom;
+ float worldMidSize = PIXEL_HANDLE_MID_SIZE / zoom;
+ float worldCenterLineThickness = PIXEL_CENTER_LINE_THICKNESS / zoom;
+ float worldCenterCrossRadius = PIXEL_CENTER_CROSS_RADIUS / zoom;
+
float minX = bounds.getMinX();
float minY = bounds.getMinY();
float maxX = bounds.getMaxX();
float maxY = bounds.getMaxY();
+
Tesselator tesselator = Tesselator.getInstance();
BufferBuilder bb = tesselator.getBuilder();
RenderSystem.enableBlend();
RenderSystem.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
- float scaledCornerSize = Math.max(4.0f, DEFAULT_CORNER_SIZE);
- float scaledMidSize = Math.max(2.0f, HANDLE_MID_SIZE);
- bb.begin(GL11.GL_LINES, 8); // 4条线 * 2个顶点 = 8个顶点
- bb.setColor(SOLID_BORDER_COLOR_MAIN);
- addLineVertices(bb, minX, minY, maxX, minY); // 上边
- addLineVertices(bb, maxX, minY, maxX, maxY); // 右边
- addLineVertices(bb, maxX, maxY, minX, maxY); // 下边
- addLineVertices(bb, minX, maxY, minX, minY); // 左边
- tesselator.end();
- bb.begin(RenderSystem.GL_TRIANGLES, (8 + 2) * 6);
- bb.setColor(HANDLE_COLOR);
- addHandleQuad(bb, minX, minY, scaledCornerSize);
- addHandleQuad(bb, maxX, minY, scaledCornerSize);
- addHandleQuad(bb, minX, maxY, scaledCornerSize);
- addHandleQuad(bb, maxX, maxY, scaledCornerSize);
- addHandleQuad(bb, (minX + maxX) * 0.5f, minY, scaledMidSize);
- addHandleQuad(bb, (minX + maxX) * 0.5f, maxY, scaledMidSize);
- addHandleQuad(bb, minX, (minY + maxY) * 0.5f, scaledMidSize);
- addHandleQuad(bb, maxX, (minY + maxY) * 0.5f, scaledMidSize);
- bb.setColor(CENTER_POINT_COLOR);
- addQuadLine(bb, pivot.x - 6.0f, pivot.y, pivot.x + 6.0f, pivot.y, CENTER_LINE_THICKNESS);
- addQuadLine(bb, pivot.x, pivot.y - 6.0f, pivot.x, pivot.y + 6.0f, CENTER_LINE_THICKNESS);
- tesselator.end();
- }
- /**
- * 添加简单的线段顶点(GL_LINES模式)
- */
- private static void addLineVertices(BufferBuilder bb, float x0, float y0, float x1, float y1) {
- bb.vertex(x0, y0, 0.0f, 0.0f);
- bb.vertex(x1, y1, 0.0f, 0.0f);
+ // 将所有绘制合并到一次 TRIANGLES 调用中
+ // 预估顶点数:4条边*6 + 8个手柄*6 + 中心十字*6*2 = 24 + 48 + 12 = 84
+ bb.begin(RenderSystem.GL_TRIANGLES, 96);
+
+ // 1. 绘制有厚度的边框
+ bb.setColor(SOLID_BORDER_COLOR_MAIN);
+ addQuadLine(bb, minX, minY, maxX, minY, worldBorderThickness); // 上边
+ addQuadLine(bb, maxX, minY, maxX, maxY, worldBorderThickness); // 右边
+ addQuadLine(bb, maxX, maxY, minX, maxY, worldBorderThickness); // 下边
+ addQuadLine(bb, minX, maxY, minX, minY, worldBorderThickness); // 左边
+
+ // 2. 绘制手柄
+ bb.setColor(HANDLE_COLOR);
+ addHandleQuad(bb, minX, minY, worldCornerSize);
+ addHandleQuad(bb, maxX, minY, worldCornerSize);
+ addHandleQuad(bb, minX, maxY, worldCornerSize);
+ addHandleQuad(bb, maxX, maxY, worldCornerSize);
+ addHandleQuad(bb, (minX + maxX) * 0.5f, minY, worldMidSize);
+ addHandleQuad(bb, (minX + maxX) * 0.5f, maxY, worldMidSize);
+ addHandleQuad(bb, minX, (minY + maxY) * 0.5f, worldMidSize);
+ addHandleQuad(bb, maxX, (minY + maxY) * 0.5f, worldMidSize);
+
+ // 3. 绘制中心点
+ bb.setColor(CENTER_POINT_COLOR);
+ addQuadLine(bb, pivot.x - worldCenterCrossRadius, pivot.y, pivot.x + worldCenterCrossRadius, pivot.y, worldCenterLineThickness);
+ addQuadLine(bb, pivot.x, pivot.y - worldCenterCrossRadius, pivot.x, pivot.y + worldCenterCrossRadius, worldCenterLineThickness);
+
+ tesselator.end();
}
/**
* 绘制多选框(虚线 + 手柄)
*
* @param multiBounds 多选包围盒
+ * @param zoom 当前摄像机的缩放值
*/
- public static void drawMultiSelectionBox(BoundingBox multiBounds) {
- if (multiBounds == null || !multiBounds.isValid()) return;
+ public static void drawMultiSelectionBox(BoundingBox multiBounds, float zoom) {
+ if (multiBounds == null || !multiBounds.isValid() || zoom <= 1e-6f) return;
+
+ // 根据 zoom 计算所有元素在世界坐标下的实际尺寸
+ float worldBorderThickness = PIXEL_MAIN_BORDER_THICKNESS / zoom;
+ float worldCornerSize = PIXEL_HANDLE_CORNER_SIZE / zoom;
+ float worldMidSize = PIXEL_HANDLE_MID_SIZE / zoom;
+ float worldCenterLineThickness = PIXEL_CENTER_LINE_THICKNESS / zoom;
+ float worldCenterCrossRadius = PIXEL_CENTER_CROSS_RADIUS / zoom;
float minX = multiBounds.getMinX();
float minY = multiBounds.getMinY();
@@ -111,157 +116,52 @@ public class MultiSelectionBoxRenderer {
Tesselator tesselator = Tesselator.getInstance();
BufferBuilder bb = tesselator.getBuilder();
-
RenderSystem.enableBlend();
RenderSystem.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
- // 1) 虚线边框(使用 GL_LINES)
+ // 合并所有绘制
int estimatedSegments = Math.max(4, (int) Math.ceil((2f * (multiBounds.getWidth() + multiBounds.getHeight())) / (DEFAULT_DASH_LENGTH + DEFAULT_GAP_LENGTH)));
- bb.begin(GL11.GL_LINES, estimatedSegments * 2);
+ bb.begin(RenderSystem.GL_TRIANGLES, estimatedSegments * 6 * 4 + 96); // 넉넉하게 할당
+
+ // 1. 绘制有厚度的虚线边框
bb.setColor(DASHED_BORDER_COLOR);
- addDashedLineVertices(bb, minX, minY, maxX, minY, DEFAULT_DASH_LENGTH, DEFAULT_GAP_LENGTH);
- addDashedLineVertices(bb, maxX, minY, maxX, maxY, DEFAULT_DASH_LENGTH, DEFAULT_GAP_LENGTH);
- addDashedLineVertices(bb, maxX, maxY, minX, maxY, DEFAULT_DASH_LENGTH, DEFAULT_GAP_LENGTH);
- addDashedLineVertices(bb, minX, maxY, minX, minY, DEFAULT_DASH_LENGTH, DEFAULT_GAP_LENGTH);
- tesselator.end();
+ addThickDashedLine(bb, minX, minY, maxX, minY, DEFAULT_DASH_LENGTH, DEFAULT_GAP_LENGTH, worldBorderThickness);
+ addThickDashedLine(bb, maxX, minY, maxX, maxY, DEFAULT_DASH_LENGTH, DEFAULT_GAP_LENGTH, worldBorderThickness);
+ addThickDashedLine(bb, maxX, maxY, minX, maxY, DEFAULT_DASH_LENGTH, DEFAULT_GAP_LENGTH, worldBorderThickness);
+ addThickDashedLine(bb, minX, maxY, minX, minY, DEFAULT_DASH_LENGTH, DEFAULT_GAP_LENGTH, worldBorderThickness);
- // 2) 手柄与中心(合并为一次三角形绘制)
- bb.begin(RenderSystem.GL_TRIANGLES, (8 + 2) * 6);
+ // 2. 绘制手柄
bb.setColor(MULTI_SELECTION_HANDLE_COLOR);
- addHandleQuad(bb, minX, minY, HANDLE_CORNER_SIZE);
- addHandleQuad(bb, maxX, minY, HANDLE_CORNER_SIZE);
- addHandleQuad(bb, minX, maxY, HANDLE_CORNER_SIZE);
- addHandleQuad(bb, maxX, maxY, HANDLE_CORNER_SIZE);
-
- addHandleQuad(bb, (minX + maxX) * 0.5f, minY, HANDLE_MID_SIZE);
- addHandleQuad(bb, (minX + maxX) * 0.5f, maxY, HANDLE_MID_SIZE);
- addHandleQuad(bb, minX, (minY + maxY) * 0.5f, HANDLE_MID_SIZE);
- addHandleQuad(bb, maxX, (minY + maxY) * 0.5f, HANDLE_MID_SIZE);
+ addHandleQuad(bb, minX, minY, worldCornerSize);
+ addHandleQuad(bb, maxX, minY, worldCornerSize);
+ addHandleQuad(bb, minX, maxY, worldCornerSize);
+ addHandleQuad(bb, maxX, maxY, worldCornerSize);
+ addHandleQuad(bb, (minX + maxX) * 0.5f, minY, worldMidSize);
+ addHandleQuad(bb, (minX + maxX) * 0.5f, maxY, worldMidSize);
+ addHandleQuad(bb, minX, (minY + maxY) * 0.5f, worldMidSize);
+ addHandleQuad(bb, maxX, (minY + maxY) * 0.5f, worldMidSize);
+ // 3. 绘制中心点
Vector2f center = multiBounds.getCenter();
bb.setColor(CENTER_POINT_COLOR);
- addQuadLine(bb, center.x - 6.0f, center.y, center.x + 6.0f, center.y, CENTER_LINE_THICKNESS);
- addQuadLine(bb, center.x, center.y - 6.0f, center.x, center.y + 6.0f, CENTER_LINE_THICKNESS);
+ addQuadLine(bb, center.x - worldCenterCrossRadius, center.y, center.x + worldCenterCrossRadius, center.y, worldCenterLineThickness);
+ addQuadLine(bb, center.x, center.y - worldCenterCrossRadius, center.x, center.y + worldCenterCrossRadius, worldCenterLineThickness);
tesselator.end();
}
+
// -------------------- 辅助绘图方法 --------------------
/**
- * 添加一个填充四边形(用两个三角形表示)
- */
- private static void addFilledQuad(BufferBuilder bb, float x0, float y0, float x1, float y1) {
- // tri 1
- bb.vertex(x0, y0, 0.0f, 0.0f);
- bb.vertex(x1, y0, 0.0f, 0.0f);
- bb.vertex(x1, y1, 0.0f, 0.0f);
- // tri 2
- bb.vertex(x1, y1, 0.0f, 0.0f);
- bb.vertex(x0, y1, 0.0f, 0.0f);
- bb.vertex(x0, y0, 0.0f, 0.0f);
- }
-
- /**
- * 手柄:以中心点绘制正方形手柄(填充)
- */
- private static void addHandleQuad(BufferBuilder bb, float cx, float cy, float size) {
- float half = size * 0.5f;
- addFilledQuad(bb, cx - half, cy - half, cx + half, cy + half);
- }
-
- /**
- * 绘制一条由四边形模拟的线段(厚度可控)
- */
- private static void addQuadLine(BufferBuilder bb, float x0, float y0, float x1, float y1, float thickness) {
- float dx = x1 - x0;
- float dy = y1 - y0;
- float len = (float) Math.sqrt(dx * dx + dy * dy);
- if (len < 1e-6f) return;
-
- float halfThick = thickness * 0.5f;
- float nx = -dy / len * halfThick;
- float ny = dx / len * halfThick;
-
- float v0x = x0 + nx; float v0y = y0 + ny;
- float v1x = x1 + nx; float v1y = y1 + ny;
- float v2x = x1 - nx; float v2y = y1 - ny;
- float v3x = x0 - nx; float v3y = y0 - ny;
-
- bb.vertex(v0x, v0y, 0.0f, 0.0f);
- bb.vertex(v1x, v1y, 0.0f, 0.0f);
- bb.vertex(v2x, v2y, 0.0f, 0.0f);
-
- bb.vertex(v2x, v2y, 0.0f, 0.0f);
- bb.vertex(v3x, v3y, 0.0f, 0.0f);
- bb.vertex(v0x, v0y, 0.0f, 0.0f);
- }
-
-
- /**
- * 绘制一个闭合的四边形线环(用于边框三层绘制)
+ * (新增) 在两点之间生成有厚度的虚线段 (使用 GL_TRIANGLES)
*
- * @param thickness 厚度(世界坐标)
- * @param vertices 顶点序列 x1,y1,x2,y2,...
+ * @param dashLen 虚线长度(世界坐标)
+ * @param gapLen 间隙长度(世界坐标)
+ * @param thickness 虚线的厚度(世界坐标)
*/
- private static void addQuadLineLoop(BufferBuilder bb, float thickness, float... vertices) {
- if (vertices == null || vertices.length < 8) return;
- int n = vertices.length / 2;
- for (int i = 0; i < n; i++) {
- float x0 = vertices[(i * 2)];
- float y0 = vertices[(i * 2) + 1];
- float x1 = vertices[((i + 1) % n) * 2];
- float y1 = vertices[((i + 1) % n) * 2 + 1];
- addQuadLine(bb, x0, y0, x1, y1, thickness);
- }
- }
-
- /**
- * 绘制圆环(由多个三角形片段组成)
- *
- * @param cx 中心 x
- * @param cy 中心 y
- * @param radius 半径
- * @param thickness 环厚度
- * @param segments 分段数(建议 >= 8)
- */
- private static void addRing(BufferBuilder bb, float cx, float cy, float radius, float thickness, int segments) {
- if (segments < 6) segments = 6;
- float halfThick = thickness * 0.5f;
- float innerR = Math.max(0.5f, radius - halfThick);
- float outerR = radius + halfThick;
-
- for (int i = 0; i < segments; i++) {
- float a0 = (float) (i * 2.0 * Math.PI / segments);
- float a1 = (float) ((i + 1) * 2.0 * Math.PI / segments);
-
- float cos0 = (float) Math.cos(a0), sin0 = (float) Math.sin(a0);
- float cos1 = (float) Math.cos(a1), sin1 = (float) Math.sin(a1);
-
- float x0i = cx + cos0 * innerR, y0i = cy + sin0 * innerR;
- float x1i = cx + cos1 * innerR, y1i = cy + sin1 * innerR;
- float x0o = cx + cos0 * outerR, y0o = cy + sin0 * outerR;
- float x1o = cx + cos1 * outerR, y1o = cy + sin1 * outerR;
-
- // tri 1
- bb.vertex(x0i, y0i, 0.0f, 0.0f);
- bb.vertex(x0o, y0o, 0.0f, 0.0f);
- bb.vertex(x1o, y1o, 0.0f, 0.0f);
- // tri 2
- bb.vertex(x1o, y1o, 0.0f, 0.0f);
- bb.vertex(x1i, y1i, 0.0f, 0.0f);
- bb.vertex(x0i, y0i, 0.0f, 0.0f);
- }
- }
-
- /**
- * 在两点之间生成虚线段顶点(使用 GL_LINES)
- *
- * @param dashLen 虚线长度(世界坐标)
- * @param gapLen 间隙长度(世界坐标)
- */
- private static void addDashedLineVertices(BufferBuilder bb, float startX, float startY, float endX, float endY,
- float dashLen, float gapLen) {
+ private static void addThickDashedLine(BufferBuilder bb, float startX, float startY, float endX, float endY,
+ float dashLen, float gapLen, float thickness) {
float dx = endX - startX;
float dy = endY - startY;
float len = (float) Math.sqrt(dx * dx + dy * dy);
@@ -281,8 +181,60 @@ public class MultiSelectionBoxRenderer {
float ex = startX + dirX * e;
float ey = startY + dirY * e;
- bb.vertex(sx, sy, 0.0f, 0.0f);
- bb.vertex(ex, ey, 0.0f, 0.0f);
+ // 为每一小段虚线绘制一个有厚度的四边形
+ addQuadLine(bb, sx, sy, ex, ey, thickness);
}
}
-}
+
+ /**
+ * 手柄:以中心点绘制正方形手柄(填充)
+ */
+ private static void addHandleQuad(BufferBuilder bb, float cx, float cy, float size) {
+ float half = size * 0.5f;
+ addFilledQuad(bb, cx - half, cy - half, cx + half, cy + half);
+ }
+
+ /**
+ * 绘制一条由四边形模拟的线段(厚度可控)
+ */
+ public static void addQuadLine(BufferBuilder bb, float x0, float y0, float x1, float y1, float thickness) {
+ float dx = x1 - x0;
+ float dy = y1 - y0;
+ float len = (float) Math.sqrt(dx * dx + dy * dy);
+ if (len < 1e-6f) return;
+
+ float halfThick = thickness * 0.5f;
+ // 计算线段的法线向量
+ float nx = -dy / len * halfThick;
+ float ny = dx / len * halfThick;
+
+ // 计算四边形的四个顶点
+ float v0x = x0 + nx; float v0y = y0 + ny;
+ float v1x = x1 + nx; float v1y = y1 + ny;
+ float v2x = x1 - nx; float v2y = y1 - ny;
+ float v3x = x0 - nx; float v3y = y0 - ny;
+
+ addQuadVertices(bb, v0x, v0y, v1x, v1y, v2x, v2y, v3x, v3y);
+ }
+
+ /**
+ * 添加一个填充四边形(用两个三角形表示)
+ */
+ public static void addFilledQuad(BufferBuilder bb, float x0, float y0, float x1, float y1) {
+ addQuadVertices(bb, x0, y0, x1, y0, x1, y1, x0, y1);
+ }
+
+ /**
+ * 辅助方法:添加构成四边形的6个顶点
+ */
+ private static void addQuadVertices(BufferBuilder bb, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3) {
+ // tri 1
+ bb.vertex(x0, y0, 0.0f, 0.0f);
+ bb.vertex(x1, y1, 0.0f, 0.0f);
+ bb.vertex(x2, y2, 0.0f, 0.0f);
+ // tri 2
+ bb.vertex(x2, y2, 0.0f, 0.0f);
+ bb.vertex(x3, y3, 0.0f, 0.0f);
+ bb.vertex(x0, y0, 0.0f, 0.0f);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/chuangzhou/vivid2D/render/TextRenderer.java b/src/main/java/com/chuangzhou/vivid2D/render/TextRenderer.java
index 21915d2..e2e5590 100644
--- a/src/main/java/com/chuangzhou/vivid2D/render/TextRenderer.java
+++ b/src/main/java/com/chuangzhou/vivid2D/render/TextRenderer.java
@@ -196,6 +196,7 @@ public final class TextRenderer {
// 按字符类型分组渲染以减少纹理切换
int currentTexture = -1;
boolean batchStarted = false;
+ builder.setColor(color);
for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
diff --git a/src/main/java/com/chuangzhou/vivid2D/render/awt/manager/ParametersManagement.java b/src/main/java/com/chuangzhou/vivid2D/render/awt/manager/ParametersManagement.java
index 1c46a73..c46b6f5 100644
--- a/src/main/java/com/chuangzhou/vivid2D/render/awt/manager/ParametersManagement.java
+++ b/src/main/java/com/chuangzhou/vivid2D/render/awt/manager/ParametersManagement.java
@@ -19,19 +19,17 @@ import java.util.*;
public class ParametersManagement {
private static final Logger logger = LoggerFactory.getLogger(ParametersManagement.class);
private final ParametersPanel parametersPanel;
- private final ModelRenderPanel renderPanel;
public List oldValues = new ArrayList<>();
public ParametersManagement(ParametersPanel parametersPanel) {
this.parametersPanel = parametersPanel;
- this.renderPanel = parametersPanel.getRenderPanel();
-
+ ModelRenderPanel renderPanel = parametersPanel.getRenderPanel();
for (int i = 0; i < renderPanel.getModel().getParts().size(); i++) {
ModelPart modelPart = renderPanel.getModel().getParts().get(i);
modelPart.addEvent((eventName, eventBus) -> {
if (eventName.equals("vertex")){
if (!(eventBus instanceof Map)) {
- System.err.println("Error: eventBus is not a Map for vertex event.");
+ logger.error("Error: eventBus is not a Map for vertex event.");
return;
}
@SuppressWarnings("unchecked")
diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/Mesh2D.java b/src/main/java/com/chuangzhou/vivid2D/render/model/Mesh2D.java
index cad7db2..b37df68 100644
--- a/src/main/java/com/chuangzhou/vivid2D/render/model/Mesh2D.java
+++ b/src/main/java/com/chuangzhou/vivid2D/render/model/Mesh2D.java
@@ -1561,54 +1561,64 @@ public class Mesh2D {
if (isSuspension && !selected) {
RenderSystem.pushState();
-
setSolidShader(modelMatrix);
-
RenderSystem.enableBlend();
RenderSystem.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
Tesselator t = Tesselator.getInstance();
BufferBuilder bb = t.getBuilder();
-
BoundingBox bbox = getBounds();
- if (bbox != null && bbox.isValid()) {
- bb.begin(GL11.GL_LINE_LOOP, 4);
+ float zoom = ModelRender.getCamera().getZoom();
+
+ if (bbox != null && bbox.isValid() && zoom > 1e-6f) {
+
+ // --- 1. 定义所有元素的期望“像素”尺寸 ---
+ final float PIXEL_BORDER_THICKNESS = 1.5f;
+ final float PIXEL_BOX_OFFSET_Y = 8.0f; // 提示框距离物体顶部的垂直像素距离
+ final float PIXEL_FONT_SIZE_BASE = 14.0f;
+ final float PIXEL_LINE_HEIGHT = 18.0f;
+ final float PIXEL_PADDING = 5.0f; // 文本背景框的内边距
+
+ // --- 2. 根据 zoom 计算出在“世界坐标”中应有的大小 ---
+ float worldBorderThickness = PIXEL_BORDER_THICKNESS / zoom;
+ float worldBoxOffsetY = PIXEL_BOX_OFFSET_Y / zoom;
+ float worldLineHeight = PIXEL_LINE_HEIGHT / zoom;
+ float worldPadding = PIXEL_PADDING / zoom;
+ float textScale = (PIXEL_FONT_SIZE_BASE / 14.0f) / zoom;
+
+ // --- 3. 绘制动态厚度的红色悬停边框 ---
+ bb.begin(GL11.GL_TRIANGLES, 4 * 6);
bb.setColor(new Vector4f(1f, 0f, 0f, 1f));
- bb.vertex(bbox.getMinX(), bbox.getMinY(), 0f, 0f);
- bb.vertex(bbox.getMaxX(), bbox.getMinY(), 0f, 0f);
- bb.vertex(bbox.getMaxX(), bbox.getMaxY(), 0f, 0f);
- bb.vertex(bbox.getMinX(), bbox.getMaxY(), 0f, 0f);
+ MultiSelectionBoxRenderer.addQuadLine(bb, bbox.getMinX(), bbox.getMinY(), bbox.getMaxX(), bbox.getMinY(), worldBorderThickness);
+ MultiSelectionBoxRenderer.addQuadLine(bb, bbox.getMaxX(), bbox.getMinY(), bbox.getMaxX(), bbox.getMaxY(), worldBorderThickness);
+ MultiSelectionBoxRenderer.addQuadLine(bb, bbox.getMaxX(), bbox.getMaxY(), bbox.getMinX(), bbox.getMaxY(), worldBorderThickness);
+ MultiSelectionBoxRenderer.addQuadLine(bb, bbox.getMinX(), bbox.getMaxY(), bbox.getMinX(), bbox.getMinY(), worldBorderThickness);
t.end();
+ // --- 4. 计算文本布局 ---
String hoverText = getName();
- float textX = bbox.getMaxX() + 5f;
- float textY = bbox.getMaxY();
- Vector4f bgColor = new Vector4f(1f, 0f, 0f, 0.8f);
- Vector4f fgColor = new Vector4f(1f, 1f, 1f, 1f);
-
- float lineHeight = 18f;
-
List lines = splitLines(hoverText, 30);
-
- float textHeight = lines.size() * lineHeight;
- float textWidth = 0f;
+ float maxTextWidth = 0f;
for (String line : lines) {
- textWidth = Math.max(textWidth, ModelRender.getTextRenderer().getTextWidth(line));
+ maxTextWidth = Math.max(maxTextWidth, ModelRender.getTextRenderer().getTextWidth(line) * textScale);
}
-
+ float totalTextHeight = (lines.size() -1) * worldLineHeight;
+ float boxX = bbox.getCenterX() - (maxTextWidth / 2f);
+ float boxY = bbox.getMaxY() + worldBoxOffsetY;
+ Vector4f bgColor = new Vector4f(1f, 0f, 0f, 0.8f);
bb.begin(GL11.GL_TRIANGLES, 6);
bb.setColor(bgColor);
- bb.vertex(textX, textY, 0f, 0f);
- bb.vertex(textX + textWidth, textY, 0f, 0f);
- bb.vertex(textX + textWidth, textY + textHeight, 0f, 0f);
- bb.vertex(textX + textWidth, textY + textHeight, 0f, 0f);
- bb.vertex(textX, textY + textHeight, 0f, 0f);
- bb.vertex(textX, textY, 0f, 0f);
+ float bgX0 = boxX - worldPadding;
+ float bgY0 = boxY - worldPadding;
+ float bgX1 = boxX + maxTextWidth + worldPadding;
+ float bgY1 = boxY + totalTextHeight + worldPadding + worldLineHeight;
+ MultiSelectionBoxRenderer.addFilledQuad(bb, bgX0, bgY0, bgX1, bgY1);
t.end();
-
+ Vector4f fgColor = new Vector4f(1f, 1f, 1f, 1f);
for (int i = 0; i < lines.size(); i++) {
String line = lines.get(i);
- ModelRender.renderText(line, textX, textY + (i + 1) * lineHeight - 5, fgColor);
+ float lineY = boxY + (lines.size() - 1 - i) * worldLineHeight;
+ ModelRender.renderText(line, boxX, lineY + 30.0f, fgColor, textScale);
}
}
@@ -1665,7 +1675,7 @@ public class Mesh2D {
private void drawSelectBox() {
BoundingBox bounds = getBounds();
- MultiSelectionBoxRenderer.drawSelectBox(bounds, pivot);
+ MultiSelectionBoxRenderer.drawSelectBox(bounds, pivot, ModelRender.getCamera().getZoom());
}
/**
@@ -1774,7 +1784,7 @@ public class Mesh2D {
*/
private void drawMultiSelectionBox() {
BoundingBox multiBounds = getMultiSelectionBounds();
- MultiSelectionBoxRenderer.drawMultiSelectionBox(multiBounds);
+ MultiSelectionBoxRenderer.drawMultiSelectionBox(multiBounds,ModelRender.getCamera().getZoom());
}
/**
diff --git a/src/main/java/com/chuangzhou/vivid2D/render/model/util/BoundingBox.java b/src/main/java/com/chuangzhou/vivid2D/render/model/util/BoundingBox.java
index dcf2158..501bf03 100644
--- a/src/main/java/com/chuangzhou/vivid2D/render/model/util/BoundingBox.java
+++ b/src/main/java/com/chuangzhou/vivid2D/render/model/util/BoundingBox.java
@@ -630,4 +630,20 @@ public class BoundingBox {
public BoundingBox copy() {
return new BoundingBox(this);
}
+
+ /**
+ * 获取包围盒的中心点 X 坐标。
+ * @return 中心点的 X 坐标
+ */
+ public float getCenterX() {
+ return (this.minX + this.maxX) * 0.5f;
+ }
+
+ /**
+ * 获取包围盒的中心点 Y 坐标。
+ * @return 中心点的 Y 坐标
+ */
+ public float getCenterY() {
+ return (this.minY + this.maxY) * 0.5f;
+ }
}
\ No newline at end of file
diff --git a/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/def/TextShader.java b/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/def/TextShader.java
index 0007641..6ea07e8 100644
--- a/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/def/TextShader.java
+++ b/src/main/java/com/chuangzhou/vivid2D/render/systems/sources/def/TextShader.java
@@ -6,7 +6,7 @@ import com.chuangzhou.vivid2D.render.systems.sources.ShaderProgram;
import org.joml.Vector4f;
/**
- * 文本着色器
+ * 文本着色器 (已修正并与渲染引擎兼容)
*
* @author tzdwindows 7
*/
@@ -14,11 +14,6 @@ public class TextShader implements CompleteShader {
private final VertexShader vertexShader = new VertexShader();
private final FragmentShader fragmentShader = new FragmentShader();
- private final Vector4f color = new Vector4f(1, 1, 1, 1);
-
- public void setColor(Vector4f color) {
- this.color.set(color);
- }
@Override
public Shader getVertexShader() {
@@ -42,12 +37,11 @@ public class TextShader implements CompleteShader {
@Override
public void setDefaultUniforms(ShaderProgram program) {
- // 传递颜色 uniform
- program.setUniform4f("uColor", color.x, color.y, color.z, color.w);
- // 纹理通常绑定到0号纹理单元
+ program.setUniform4f("uColor", 1.0f, 1.0f, 1.0f, 1.0f);
program.setUniform1i("uTexture", 0);
}
+ // --- Vertex Shader (已适配 mat3 和 uCameraZ) ---
private static class VertexShader implements Shader {
@Override
public String getShaderCode() {
@@ -56,12 +50,18 @@ public class TextShader implements CompleteShader {
layout(location = 0) in vec2 aPosition;
layout(location = 1) in vec2 aTexCoord;
+ uniform mat3 uModelMatrix;
+ uniform mat3 uViewMatrix;
uniform mat3 uProjectionMatrix;
+
+ uniform float uCameraZ;
out vec2 vTexCoord;
void main() {
- vec3 p = uProjectionMatrix * vec3(aPosition, 1.0);
+ vec3 p = uProjectionMatrix * uViewMatrix * uModelMatrix * vec3(aPosition, 1.0);
+
+ // 输出为 gl_Position (vec4)
gl_Position = vec4(p.xy, 0.0, 1.0);
vTexCoord = aTexCoord;
}
@@ -86,9 +86,11 @@ public class TextShader implements CompleteShader {
uniform vec4 uColor;
void main() {
- // 使用 .r 通道读取单通道纹理
float alpha = texture(uTexture, vTexCoord).r;
FragColor = vec4(uColor.rgb, uColor.a * alpha);
+ if (FragColor.a < 0.01) {
+ discard;
+ }
}
""";
}
@@ -98,4 +100,4 @@ public class TextShader implements CompleteShader {
return "TextFragmentShader";
}
}
-}
+}
\ No newline at end of file