From 6b335310e8d4a8043830c3fb2c29e200ff8c49b1 Mon Sep 17 00:00:00 2001 From: austin Date: Wed, 28 May 2025 21:11:15 -0400 Subject: [PATCH] fix prism meshgen + farm plot geom --- buildNumber.properties | 4 +- docs/src/progress/renderertodo.md | 2 + .../electrosphere/entity/DrawableUtils.java | 29 +++++++++ .../electrosphere/renderer/RenderUtils.java | 13 ++++ .../renderer/actor/ActorUtils.java | 5 ++ .../renderer/meshgen/GeometryMeshGen.java | 60 ++++++++++++++----- .../electrosphere/renderer/model/Mesh.java | 3 + .../pipelines/debug/DebugContentPipeline.java | 36 +++++++++++ .../server/macro/town/TownLayout.java | 17 +++--- .../util/math/region/RegionPrism.java | 32 ++++++---- 10 files changed, 166 insertions(+), 35 deletions(-) diff --git a/buildNumber.properties b/buildNumber.properties index df7b4d76..4a46a5b5 100644 --- a/buildNumber.properties +++ b/buildNumber.properties @@ -1,3 +1,3 @@ #maven.buildNumber.plugin properties file -#Wed May 28 11:59:04 EDT 2025 -buildNumber=639 +#Wed May 28 21:00:17 EDT 2025 +buildNumber=643 diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index 789da4bb..fb13e1e5 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -2039,6 +2039,8 @@ Scaffolding for laying out farm plots around towns Region interface Town layout non-statically generates farm plots Y-aligned prism meshgen +Rendering prism regions +Utilities for turning mesh gen algos into renderable entities diff --git a/src/main/java/electrosphere/entity/DrawableUtils.java b/src/main/java/electrosphere/entity/DrawableUtils.java index bde0f546..eba46d4f 100644 --- a/src/main/java/electrosphere/entity/DrawableUtils.java +++ b/src/main/java/electrosphere/entity/DrawableUtils.java @@ -3,13 +3,20 @@ package electrosphere.entity; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.concurrent.Callable; +import org.joml.Quaterniond; +import org.joml.Vector3d; import org.joml.Vector3f; import electrosphere.data.entity.graphics.NonproceduralModel; import electrosphere.engine.Globals; +import electrosphere.engine.assetmanager.queue.QueuedModel; import electrosphere.entity.state.idle.ClientIdleTree; +import electrosphere.renderer.RenderUtils; import electrosphere.renderer.actor.Actor; +import electrosphere.renderer.actor.ActorUtils; +import electrosphere.renderer.model.Mesh; /** * Utilities to manipulating drawable entities (eg making an entity transparent) @@ -96,4 +103,26 @@ public class DrawableUtils { } } + /** + * Makes an entity drawable with a mesh to be generated via a callback + * @param entity The entity + * @param meshGenerator The callback to generate a mesh + */ + public static void makeEntityDrawable(Entity entity, Callable meshGenerator){ + QueuedModel model = new QueuedModel(() -> { + Mesh mesh = meshGenerator.call(); + return RenderUtils.wrapMeshInModel(mesh); + }); + String path = Globals.assetManager.queuedAsset(model); + entity.putData(EntityDataStrings.DATA_STRING_ACTOR, ActorUtils.createActorOfLoadingModel(path)); + entity.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0)); + entity.putData(EntityDataStrings.DATA_STRING_ROTATION, new Quaterniond().identity()); + entity.putData(EntityDataStrings.DATA_STRING_SCALE, new Vector3f(1,1,1)); + entity.putData(EntityDataStrings.DATA_STRING_DRAW, true); + entity.putData(EntityDataStrings.DRAW_SOLID_PASS, true); + Globals.clientState.clientScene.registerEntityToTag(entity, EntityTags.DRAWABLE); + Globals.clientState.clientScene.registerEntityToTag(entity, EntityTags.DRAW_VOLUMETIC_SOLIDS_PASS); + Globals.clientState.clientScene.registerEntityToTag(entity, EntityTags.DRAW_CAST_SHADOW); + } + } diff --git a/src/main/java/electrosphere/renderer/RenderUtils.java b/src/main/java/electrosphere/renderer/RenderUtils.java index d7352653..76e5ad2e 100644 --- a/src/main/java/electrosphere/renderer/RenderUtils.java +++ b/src/main/java/electrosphere/renderer/RenderUtils.java @@ -630,6 +630,19 @@ public class RenderUtils { return model; } + /** + * Wraps a mesh in a model + * @param mesh The mesh + * @return The model that wraps the mesh + */ + public static Model wrapMeshInModel(Mesh mesh){ + Model model = new Model(); + //setup extra structures + mesh.setParent(model); + model.getMeshes().add(mesh); + return model; + } + @Deprecated public static Model createBitmapDisplay(){ diff --git a/src/main/java/electrosphere/renderer/actor/ActorUtils.java b/src/main/java/electrosphere/renderer/actor/ActorUtils.java index f2de3ae4..7b0b0fb9 100644 --- a/src/main/java/electrosphere/renderer/actor/ActorUtils.java +++ b/src/main/java/electrosphere/renderer/actor/ActorUtils.java @@ -20,6 +20,11 @@ public class ActorUtils { return rVal; } + /** + * Creates an actor from an already-loading path + * @param modelPath The path + * @return The actor + */ public static Actor createActorOfLoadingModel(String modelPath){ Actor rVal = new Actor(modelPath); return rVal; diff --git a/src/main/java/electrosphere/renderer/meshgen/GeometryMeshGen.java b/src/main/java/electrosphere/renderer/meshgen/GeometryMeshGen.java index e61c89de..4d62d864 100644 --- a/src/main/java/electrosphere/renderer/meshgen/GeometryMeshGen.java +++ b/src/main/java/electrosphere/renderer/meshgen/GeometryMeshGen.java @@ -299,8 +299,8 @@ public class GeometryMeshGen { Vector3d centerpoint = new Vector3d(points[0]); for(int i = 1; i < points.length; i++){ centerpoint = centerpoint.add(points[i]); - centerpoint = centerpoint.mul(1.0f / (float)points.length); } + centerpoint = centerpoint.mul(1.0f / (float)points.length); //allocate buffers @@ -323,7 +323,7 @@ public class GeometryMeshGen { normalBuffer.put(-1f); normalBuffer.put(0f); normalBuffer.put(0f); - normalBuffer.put(11f); + normalBuffer.put(1f); normalBuffer.put(0f); uvBuffer.put(0); uvBuffer.put(0); @@ -353,23 +353,31 @@ public class GeometryMeshGen { uvBuffer.put(1); uvBuffer.put(1); uvBuffer.put(1); + int p1index = ((i + 0) * 2) + 2; + int p2index = ((i + 0) * 2) + 3; + int p3index = ((i + 1) * 2) + 2; + int p4index = ((i + 1) * 2) + 3; //add face data //bottom triangle faceBuffer.put(0); - faceBuffer.put(((i + 0) * 2) + 0); - faceBuffer.put(((i + 1) * 2) + 0); + faceBuffer.put(p1index); + faceBuffer.put(p3index); //top triangle faceBuffer.put(1); - faceBuffer.put(((i + 0) * 2) + 1); - faceBuffer.put(((i + 1) * 2) + 1); + faceBuffer.put(p2index); + faceBuffer.put(p4index); //perimeter face 1 - faceBuffer.put(((i + 0) * 2) + 0); - faceBuffer.put(((i + 1) * 2) + 0); - faceBuffer.put(((i + 0) * 2) + 1); + faceBuffer.put(p2index); + faceBuffer.put(p1index); + faceBuffer.put(p3index); //perimeter face 2 - faceBuffer.put(((i + 1) * 2) + 0); - faceBuffer.put(((i + 0) * 2) + 1); - faceBuffer.put(((i + 1) * 2) + 1); + faceBuffer.put(p2index); + faceBuffer.put(p3index); + faceBuffer.put(p4index); + // System.out.println(p2index + "--" + p4index); + // System.out.println("|\\ |"); + // System.out.println("| \\|"); + // System.out.println(p1index + "--" + p3index); } // @@ -392,11 +400,31 @@ public class GeometryMeshGen { uvBuffer.put(1); uvBuffer.put(1); uvBuffer.put(1); + //add face data + int p1index = (3 * 2) + 2; + int p2index = (3 * 2) + 3; + int p3index = (0 * 2) + 2; + int p4index = (0 * 2) + 3; + //bottom triangle + faceBuffer.put(0); + faceBuffer.put(p1index); + faceBuffer.put(p3index); + //top triangle + faceBuffer.put(1); + faceBuffer.put(p2index); + faceBuffer.put(p4index); + //perimeter face 1 + faceBuffer.put(p2index); + faceBuffer.put(p1index); + faceBuffer.put(p3index); + //perimeter face 2 + faceBuffer.put(p2index); + faceBuffer.put(p3index); + faceBuffer.put(p4index); //actually store in mesh - int elementCount = points.length * 12; try { //actually buffer vertices if(vertBuffer.position() > 0){ @@ -404,19 +432,19 @@ public class GeometryMeshGen { mesh.bufferVertices(vertBuffer, 3); } //actually buffer normals - if(normalBuffer != null && normalBuffer.position() > 0){ + if(normalBuffer.position() > 0){ normalBuffer.flip(); mesh.bufferNormals(normalBuffer, 3); } //actually buffer UVs - if(uvBuffer != null && uvBuffer.position() > 0){ + if(uvBuffer.position() > 0){ uvBuffer.flip(); mesh.bufferTextureCoords(uvBuffer, 2); } //buffer element indices if(faceBuffer.position() > 0){ faceBuffer.flip(); - mesh.bufferFaces(faceBuffer, elementCount); + mesh.bufferFaces(faceBuffer, faceBuffer.limit()); } } catch (NullPointerException ex){ ex.printStackTrace(); diff --git a/src/main/java/electrosphere/renderer/model/Mesh.java b/src/main/java/electrosphere/renderer/model/Mesh.java index fd0ab5c6..be69810d 100644 --- a/src/main/java/electrosphere/renderer/model/Mesh.java +++ b/src/main/java/electrosphere/renderer/model/Mesh.java @@ -456,6 +456,9 @@ public class Mesh { if(selectedProgram == null){ selectedProgram = shader; } + if(selectedProgram == null){ + selectedProgram = Globals.defaultMeshShader; + } openGLState.setActiveShader(renderPipelineState, selectedProgram); Globals.profiler.endCpuSample(); } diff --git a/src/main/java/electrosphere/renderer/pipelines/debug/DebugContentPipeline.java b/src/main/java/electrosphere/renderer/pipelines/debug/DebugContentPipeline.java index 79510923..5bf0e529 100644 --- a/src/main/java/electrosphere/renderer/pipelines/debug/DebugContentPipeline.java +++ b/src/main/java/electrosphere/renderer/pipelines/debug/DebugContentPipeline.java @@ -29,7 +29,10 @@ import electrosphere.data.entity.common.CommonEntityType; import electrosphere.data.entity.grident.GridAlignedData; import electrosphere.engine.Globals; import electrosphere.engine.assetmanager.AssetDataStrings; +import electrosphere.entity.ClientEntityUtils; +import electrosphere.entity.DrawableUtils; import electrosphere.entity.Entity; +import electrosphere.entity.EntityCreationUtils; import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityTags; import electrosphere.entity.EntityUtils; @@ -39,6 +42,7 @@ import electrosphere.entity.types.common.CommonEntityUtils; import electrosphere.renderer.OpenGLState; import electrosphere.renderer.RenderPipelineState; import electrosphere.renderer.RenderingEngine; +import electrosphere.renderer.meshgen.GeometryMeshGen; import electrosphere.renderer.model.Model; import electrosphere.renderer.pipelines.RenderPipeline; import electrosphere.renderer.texture.Texture; @@ -47,6 +51,8 @@ import electrosphere.server.datacell.utils.EntityLookupUtils; import electrosphere.server.macro.civilization.road.Road; import electrosphere.server.macro.structure.VirtualStructure; import electrosphere.util.math.SpatialMathUtils; +import electrosphere.util.math.region.Region; +import electrosphere.util.math.region.RegionPrism; /** * Pipeline for rendering content to assist debugging @@ -56,6 +62,11 @@ public class DebugContentPipeline implements RenderPipeline { //The bone debugging pipeline DebugBonesPipeline debugBonesPipeline = new DebugBonesPipeline(); + /** + * The farm plot macro data entities to draw + */ + private List farmPlotEntities = new LinkedList(); + @Override public void render(OpenGLState openGLState, RenderPipelineState renderPipelineState) { Globals.profiler.beginCpuSample("DebugContentPipeline.render"); @@ -210,6 +221,31 @@ public class DebugContentPipeline implements RenderPipeline { for(Road road : Globals.serverState.realmManager.first().getMacroData().getRoads()){ DebugContentPipeline.renderTube(openGLState, renderPipelineState, modelTransformMatrix, road.getPoint1(), road.getPoint2(), road.getRadius(), AssetDataStrings.TEXTURE_BLUE_TRANSPARENT); } + if(this.farmPlotEntities.isEmpty()){ + if(Globals.serverState.realmManager.first().getMacroData().getTown(0).getFarmPlots().size() > 0){ + for(Region region : Globals.serverState.realmManager.first().getMacroData().getTown(0).getFarmPlots()){ + if(region instanceof RegionPrism prism){ + Entity plotDebugEnt = EntityCreationUtils.createClientSpatialEntity(); + DrawableUtils.makeEntityDrawable(plotDebugEnt, () -> { + Vector3d[] finalPoints = new Vector3d[prism.getPoints().length]; + for(int i = 0; i < finalPoints.length; i++){ + finalPoints[i] = new Vector3d(prism.getPoints()[i]).sub(prism.getAABB().minX,prism.getAABB().minY,prism.getAABB().minZ); + } + return GeometryMeshGen.genPrism(finalPoints, prism.getHeight()); + }); + EntityUtils.getPosition(plotDebugEnt).set(prism.getAABB().minX,prism.getAABB().minY,prism.getAABB().minZ); + this.farmPlotEntities.add(plotDebugEnt); + } + } + } + } + } else { + if(!this.farmPlotEntities.isEmpty()){ + for(Entity entity : this.farmPlotEntities){ + ClientEntityUtils.destroyEntity(entity); + } + this.farmPlotEntities.clear(); + } } // diff --git a/src/main/java/electrosphere/server/macro/town/TownLayout.java b/src/main/java/electrosphere/server/macro/town/TownLayout.java index a02c6cca..b6f32937 100644 --- a/src/main/java/electrosphere/server/macro/town/TownLayout.java +++ b/src/main/java/electrosphere/server/macro/town/TownLayout.java @@ -272,11 +272,11 @@ public class TownLayout { //this is +0,+0 plotPoint1.set(currPoint); scanPoint.set(townCenter).add(TOWN_LAYOUT_SCALER * (x + 1),0,TOWN_LAYOUT_SCALER * (z + 0)); - plotPoint2.set(scanPoint); + plotPoint2 = TownLayout.getTownCenter(realm, scanPoint); scanPoint.set(townCenter).add(TOWN_LAYOUT_SCALER * (x + 1),0,TOWN_LAYOUT_SCALER * (z + 1)); - plotPoint3.set(scanPoint); + plotPoint3 = TownLayout.getTownCenter(realm, scanPoint); scanPoint.set(townCenter).add(TOWN_LAYOUT_SCALER * (x + 0),0,TOWN_LAYOUT_SCALER * (z + 1)); - plotPoint4.set(scanPoint); + plotPoint4 = TownLayout.getTownCenter(realm, scanPoint); if( plotPoint1.distance(townCenter) > TOWN_CENTER_RADIUS && plotPoint2.distance(townCenter) > TOWN_CENTER_RADIUS && @@ -284,6 +284,9 @@ public class TownLayout { plotPoint4.distance(townCenter) > TOWN_CENTER_RADIUS ){ plotPoint1.y = realm.getServerWorldData().getServerTerrainManager().getElevation(plotPoint1); + plotPoint2.y = plotPoint1.y; + plotPoint3.y = plotPoint1.y; + plotPoint4.y = plotPoint1.y; //define a farm plot with these points TownLayout.generateFarmPlot(realm,town,plotPoint1,plotPoint2,plotPoint3,plotPoint4); } @@ -413,10 +416,10 @@ public class TownLayout { */ private static void generateFarmPlot(Realm realm, Town town, Vector3d point1, Vector3d point2, Vector3d point3, Vector3d point4){ RegionPrism region = RegionPrism.create(new Vector3d[]{ - new Vector3d(point1).add(0,FARM_PLOT_DEFAULT_HEIGHT/2.0f,0), - new Vector3d(point2).add(0,FARM_PLOT_DEFAULT_HEIGHT/2.0f,0), - new Vector3d(point3).add(0,FARM_PLOT_DEFAULT_HEIGHT/2.0f,0), - new Vector3d(point4).add(0,FARM_PLOT_DEFAULT_HEIGHT/2.0f,0), + new Vector3d(point1).sub(0,FARM_PLOT_DEFAULT_HEIGHT/2.0f,0), + new Vector3d(point2).sub(0,FARM_PLOT_DEFAULT_HEIGHT/2.0f,0), + new Vector3d(point3).sub(0,FARM_PLOT_DEFAULT_HEIGHT/2.0f,0), + new Vector3d(point4).sub(0,FARM_PLOT_DEFAULT_HEIGHT/2.0f,0), }, FARM_PLOT_DEFAULT_HEIGHT); town.addFarmPlot(region); } diff --git a/src/main/java/electrosphere/util/math/region/RegionPrism.java b/src/main/java/electrosphere/util/math/region/RegionPrism.java index c9285bb3..3321a128 100644 --- a/src/main/java/electrosphere/util/math/region/RegionPrism.java +++ b/src/main/java/electrosphere/util/math/region/RegionPrism.java @@ -48,25 +48,37 @@ public class RegionPrism implements Region { if(rVal.aabb.minX > points[i].x){ rVal.aabb.minX = points[i].x; } - if(rVal.aabb.minX > points[i].y){ - rVal.aabb.minX = points[i].y; - } - if(rVal.aabb.minX > points[i].z){ - rVal.aabb.minX = points[i].z; + if(rVal.aabb.minZ > points[i].z){ + rVal.aabb.minZ = points[i].z; } if(rVal.aabb.maxX < points[i].x){ rVal.aabb.maxX = points[i].x; } - if(rVal.aabb.maxX < points[i].y){ - rVal.aabb.maxX = points[i].y; - } - if(rVal.aabb.maxX < points[i].z){ - rVal.aabb.maxX = points[i].z; + if(rVal.aabb.maxZ < points[i].z){ + rVal.aabb.maxZ = points[i].z; } } + rVal.aabb.minY = points[0].y; + rVal.aabb.maxY = points[0].y + height; return rVal; } + /** + * Gets the height of the prism + * @return The height + */ + public double getHeight(){ + return this.height; + } + + /** + * Gets the points of the prism + * @return The points of the prism + */ + public Vector3d[] getPoints(){ + return this.points; + } + @Override public RegionType getType() { return RegionType.Y_ALIGNED_PRISM;