feat(render): 添加光源与物理系统支持

- 新增 BufferBuilder 工具类用于简化顶点数据提交
- 实现 LightSource 和 LightSourceData 类以支持光源管理- 在 Model2D 中集成光源系统,支持序列化与反序列化
- 扩展 ModelData 以支持物理系统数据的完整序列化
- 重构 ModelRender以支持物理系统应用及碰撞箱渲染
- 添加粒子、弹簧、约束与碰撞体的数据结构与序列化逻辑
- 实现变形器的序列化接口以支持参数驱动动画的持久化
This commit is contained in:
tzdwindows 7
2025-10-11 20:21:11 +08:00
parent 22af92cd84
commit 9cde0192fd
18 changed files with 3071 additions and 276 deletions

View File

@@ -3,12 +3,8 @@ package com.chuangzhou.vivid2D.test;
import com.chuangzhou.vivid2D.render.model.Model2D;
import com.chuangzhou.vivid2D.render.model.ModelPart;
import com.chuangzhou.vivid2D.render.model.AnimationParameter;
import com.chuangzhou.vivid2D.render.model.util.Mesh2D;
import com.chuangzhou.vivid2D.render.model.util.AnimationLayer;
import com.chuangzhou.vivid2D.render.model.util.PhysicsSystem;
import com.chuangzhou.vivid2D.render.model.util.ModelPose;
import com.chuangzhou.vivid2D.render.model.util.BoundingBox;
import com.chuangzhou.vivid2D.render.model.util.Texture;
import com.chuangzhou.vivid2D.render.model.transform.WaveDeformer;
import com.chuangzhou.vivid2D.render.model.util.*;
import org.joml.Vector2f;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWErrorCallback;
@@ -46,7 +42,8 @@ public class ModelTest {
testPhysicsSystem();
testComplexTransformations();
testPerformance();
Model2D model = createTestModel();
printModelState(model);
} finally {
// Cleanup OpenGL
cleanupOpenGL();
@@ -55,6 +52,231 @@ public class ModelTest {
System.out.println("=== Model2D Extended Save and Load Test Complete ===");
}
public static Model2D createTestModel() {
Model2D model = new Model2D("full_test_model");
model.setVersion("1.0.0");
// ==================== 创建部件层级 ====================
ModelPart root = model.createPart("root");
ModelPart body = model.createPart("body");
ModelPart head = model.createPart("head");
ModelPart leftArm = model.createPart("left_arm");
ModelPart rightArm = model.createPart("right_arm");
root.addChild(body);
body.addChild(head);
body.addChild(leftArm);
body.addChild(rightArm);
// ==================== 设置本地变换 ====================
root.setPosition(0, 0);
root.setRotation(0f);
root.setScale(1f, 1f);
body.setPosition(0, -50);
body.setRotation(10f); // body稍微旋转
body.setScale(1.1f, 1.0f);
head.setPosition(0, -50);
head.setRotation(-5f);
head.setScale(1.0f, 1.0f);
leftArm.setPosition(-30, -20);
leftArm.setRotation(20f);
leftArm.setScale(1.0f, 0.9f);
rightArm.setPosition(30, -20);
rightArm.setRotation(-20f);
rightArm.setScale(1.0f, 0.9f);
// ==================== 添加网格 ====================
Mesh2D bodyMesh = Mesh2D.createQuad("body_mesh", 40, 80);
Mesh2D headMesh = Mesh2D.createQuad("head_mesh", 50, 50);
Mesh2D leftArmMesh = Mesh2D.createQuad("left_arm_mesh", 15, 50);
Mesh2D rightArmMesh = Mesh2D.createQuad("right_arm_mesh", 15, 50);
model.addMesh(bodyMesh);
model.addMesh(headMesh);
model.addMesh(leftArmMesh);
model.addMesh(rightArmMesh);
body.addMesh(bodyMesh);
head.addMesh(headMesh);
leftArm.addMesh(leftArmMesh);
rightArm.addMesh(rightArmMesh);
// ==================== 添加纹理 ====================
Texture bodyTex = Texture.createSolidColor("body_tex", 64, 64, 0xFFFF0000);
Texture headTex = Texture.createSolidColor("head_tex", 64, 64, 0xFF00FF00);
Texture armTex = Texture.createSolidColor("arm_tex", 32, 64, 0xFF0000FF);
bodyTex.ensurePixelDataCached();
headTex.ensurePixelDataCached();
armTex.ensurePixelDataCached();
model.addTexture(bodyTex);
model.addTexture(headTex);
model.addTexture(armTex);
bodyMesh.setTexture(bodyTex);
headMesh.setTexture(headTex);
leftArmMesh.setTexture(armTex);
rightArmMesh.setTexture(armTex);
// ==================== 添加动画参数 ====================
AnimationParameter smileParam = model.createParameter("smile", 0, 1, 0.5f);
AnimationParameter walkParam = model.createParameter("walk", 0, 1, 0);
AnimationParameter waveParam = model.createParameter("wave", 0, 1, 0);
// ==================== 添加 Deformer ====================
root.addDeformer(new WaveDeformer("blink"));
root.addDeformer(new WaveDeformer("wave"));
root.addDeformer(new WaveDeformer("blink"));
// ==================== 设置元数据 ====================
model.getMetadata().setAuthor("Test Author");
model.getMetadata().setDescription("This is a full-featured test model with transforms and deformers.");
model.getMetadata().setLicense("MIT");
model.getMetadata().setFileFormatVersion("1.0.0");
model.getMetadata().setUnitsPerMeter(100.0f);
model.getMetadata().setProperty("custom_prop1", "value1");
// ==================== 添加物理 ====================
PhysicsSystem physics = model.getPhysics();
if (physics != null) {
physics.initialize();
PhysicsSystem.PhysicsParticle p1 = physics.addParticle("p1", new Vector2f(0, 0), 1f);
PhysicsSystem.PhysicsParticle p2 = physics.addParticle("p2", new Vector2f(10, 0), 1f);
physics.addSpring("spring1", p1, p2, 10f, 0.5f, 0.1f);
}
return model;
}
public static void testModelSaveLoadIntegrity(Model2D model, String filePath) {
System.out.println("\n--- Test: Model Save and Load Integrity ---");
try {
// 保存模型
model.saveToFile(filePath);
// 加载模型
Model2D loaded = Model2D.loadFromFile(filePath);
boolean integrityOk = true;
// ==================== 基本属性 ====================
if (!model.getName().equals(loaded.getName())) {
System.out.println("Name mismatch!");
integrityOk = false;
}
if (!model.getVersion().equals(loaded.getVersion())) {
System.out.println("Version mismatch!");
integrityOk = false;
}
// ==================== 部件 ====================
if (model.getParts().size() != loaded.getParts().size()) {
System.out.println("Parts count mismatch!");
integrityOk = false;
} else {
for (int i = 0; i < model.getParts().size(); i++) {
ModelPart orig = model.getParts().get(i);
ModelPart loadPart = loaded.getParts().get(i);
if (!orig.getName().equals(loadPart.getName())) {
System.out.println("Part name mismatch: " + orig.getName());
integrityOk = false;
}
// 检查变换
if (!orig.getPosition().equals(loadPart.getPosition()) ||
orig.getRotation() != loadPart.getRotation() ||
!orig.getScale().equals(loadPart.getScale())) {
System.out.println("Part transform mismatch: " + orig.getName());
integrityOk = false;
}
// 检查Deformer
if (orig.getDeformers().size() != loadPart.getDeformers().size()) {
System.out.println("Deformer count mismatch on part: " + orig.getName());
integrityOk = false;
}
}
}
// ==================== 网格 ====================
if (model.getMeshes().size() != loaded.getMeshes().size()) {
System.out.println("Meshes count mismatch!");
integrityOk = false;
}
// ==================== 纹理 ====================
if (model.getTextures().size() != loaded.getTextures().size()) {
System.out.println("Textures count mismatch!");
integrityOk = false;
}
// ==================== 参数 ====================
if (model.getParameters().size() != loaded.getParameters().size()) {
System.out.println("Parameters count mismatch!");
integrityOk = false;
} else {
for (String key : model.getParameters().keySet()) {
AnimationParameter origParam = model.getParameters().get(key);
AnimationParameter loadParam = loaded.getParameters().get(key);
if (origParam.getValue() != loadParam.getValue()) {
System.out.println("Parameter value mismatch: " + key);
integrityOk = false;
}
}
}
// ==================== 物理 ====================
PhysicsSystem origPhysics = model.getPhysics();
PhysicsSystem loadPhysics = loaded.getPhysics();
if ((origPhysics != null && loadPhysics == null) || (origPhysics == null && loadPhysics != null)) {
System.out.println("Physics system missing after load!");
integrityOk = false;
} else if (origPhysics != null) {
if (origPhysics.getParticles().size() != loadPhysics.getParticles().size()) {
System.out.println("Physics particle count mismatch!");
integrityOk = false;
}
if (origPhysics.getSprings().size() != loadPhysics.getSprings().size()) {
System.out.println("Physics spring count mismatch!");
integrityOk = false;
}
}
System.out.println("Integrity test " + (integrityOk ? "PASSED" : "FAILED"));
} catch (Exception e) {
System.err.println("Error in testModelSaveLoadIntegrity: " + e.getMessage());
e.printStackTrace();
}
}
private static void printModelState(Model2D model) {
System.out.println(" - Name: " + model.getName());
System.out.println(" - Version: " + model.getVersion());
System.out.println(" - Parts: " + model.getParts().size());
for (ModelPart part : model.getParts()) {
printPartHierarchy(part, 1);
}
System.out.println(" - Parameters:");
for (AnimationParameter param : model.getParameters().values()) {
System.out.println(" * " + param.getId() + " = " + param.getValue());
}
System.out.println(" - Textures:");
model.getTextures().forEach((k, tex) -> {
System.out.println(" * " + tex.getName() + " (" + tex.getWidth() + "x" + tex.getHeight() + ")");
});
System.out.println(" - User Properties:");
model.getMetadata().getUserProperties().forEach((k, v) ->
System.out.println(" * " + k + ": " + v)
);
}
/**
* Initialize OpenGL context for texture testing
*/
@@ -586,6 +808,8 @@ public class ModelTest {
}
}
/**
* Utility method to print part hierarchy
*/