support for low lod models definitions and pipe
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit

This commit is contained in:
austin 2025-05-24 17:42:49 -04:00
parent 6e55b7ee18
commit ae72912649
8 changed files with 206 additions and 46 deletions

View File

@ -588,7 +588,8 @@
"priorityCategory" : "IDLE"
}
},
"path" : "Models/creatures/person2/person2_1.glb"
"path" : "Models/creatures/person2/person2_1.glb",
"lodPath": "Models/creatures/person2/person2_1_lod.glb"
}
},
"viewModelData" : {

Binary file not shown.

View File

@ -68,6 +68,7 @@ public class PhysicsEntityUtils {
if(physicsTemplate.getKinematic()){
categoryBit = Collidable.TYPE_STATIC_BIT;
}
CollisionEngine.lockOde();
if(physicsTemplate.getKinematic()){
DGeom geom = null;
switch(physicsTemplate.getType()){
@ -364,6 +365,7 @@ public class PhysicsEntityUtils {
ClientPhysicsSyncTree.attachTree(rVal);
}
}
CollisionEngine.unlockOde();
}
@ -383,6 +385,7 @@ public class PhysicsEntityUtils {
if(physicsTemplate.getKinematic()){
categoryBit = Collidable.TYPE_STATIC_BIT;
}
CollisionEngine.lockOde();
if(physicsTemplate.getKinematic()){
DGeom geom = null;
switch(physicsTemplate.getType()){
@ -686,6 +689,7 @@ public class PhysicsEntityUtils {
ServerPhysicsSyncTree.attachTree(rVal);
}
}
CollisionEngine.unlockOde();
}

View File

@ -31,6 +31,11 @@ public class NonproceduralModel {
*/
private Map<String,Vector3f> meshColorMap;
/**
* The path to the lower-resolution model
*/
private String lodPath;
/**
* Gets the path of the model
* @return The path of the model
@ -94,6 +99,22 @@ public class NonproceduralModel {
public void setMeshColorMap(Map<String,Vector3f> meshColorMap) {
this.meshColorMap = meshColorMap;
}
/**
* Gets the path to the lower resolution model
* @return The path to the lower resolution model
*/
public String getLODPath(){
return lodPath;
}
/**
* Sets the path to the lower resolution model
* @param lodPath The path to the lower resolution model
*/
public void setLODPath(String lodPath){
this.lodPath = lodPath;
}
}

View File

@ -1,5 +1,14 @@
package electrosphere.entity;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.joml.Vector3f;
import electrosphere.data.entity.graphics.NonproceduralModel;
import electrosphere.engine.Globals;
import electrosphere.entity.state.idle.ClientIdleTree;
import electrosphere.renderer.actor.Actor;
/**
@ -36,4 +45,55 @@ public class DrawableUtils {
return entity.containsKey(EntityDataStrings.HAS_UNIQUE_MODEL);
}
/**
* Applies non-procedural model data to the entity
* @param entity The entity
* @param modelData The model data
*/
public static void applyNonproceduralModel(Entity entity, NonproceduralModel modelData){
if(modelData == null){
throw new Error("Null model data!");
}
if(modelData.getPath() == null){
throw new Error("Path undefined!");
}
//make the entity drawable
EntityCreationUtils.makeEntityDrawable(entity, modelData.getPath());
Actor creatureActor = EntityUtils.getActor(entity);
//add low-res model path to actor if present
if(modelData.getLODPath() != null){
creatureActor.setLowResPath(modelData.getLODPath());
Globals.assetManager.addModelPathToQueue(modelData.getLODPath());
}
//idle tree & generic stuff all entities have
if(modelData.getIdleData() != null){
ClientIdleTree.attachTree(entity, modelData.getIdleData());
}
//apply uniforms
if(modelData.getUniforms() != null){
Map<String,Map<String,Object>> meshUniformMap = modelData.getUniforms();
Set<String> meshNames = meshUniformMap.keySet();
for(String meshName : meshNames){
Map<String,Object> uniforms = meshUniformMap.get(meshName);
Set<String> uniformNames = uniforms.keySet();
for(String uniformName : uniformNames){
Object value = uniforms.get(uniformName);
creatureActor.setUniformOnMesh(meshName, uniformName, value);
}
}
}
//apply mesh color map
if(modelData.getMeshColorMap() != null){
Map<String,Vector3f> meshColorMap = modelData.getMeshColorMap();
for(Entry<String,Vector3f> entry : meshColorMap.entrySet()){
creatureActor.setUniformOnMesh(entry.getKey(), "color", entry.getValue());
}
}
}
}

View File

@ -1,12 +1,7 @@
package electrosphere.entity.types.common;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.joml.Quaterniond;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.ode4j.ode.DBody;
import electrosphere.client.interact.ClientInteractionEngine;
@ -31,6 +26,7 @@ import electrosphere.data.entity.graphics.GraphicsTemplate;
import electrosphere.data.entity.item.Item;
import electrosphere.engine.Globals;
import electrosphere.engine.assetmanager.PhysicsMeshQueueItem;
import electrosphere.entity.DrawableUtils;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityCreationUtils;
import electrosphere.entity.EntityDataStrings;
@ -55,7 +51,6 @@ import electrosphere.entity.state.gravity.ServerGravityTree;
import electrosphere.entity.state.growth.ClientGrowthComponent;
import electrosphere.entity.state.growth.ServerGrowthComponent;
import electrosphere.entity.state.hitbox.HitboxCollectionState;
import electrosphere.entity.state.idle.ClientIdleTree;
import electrosphere.entity.state.idle.ServerIdleTree;
import electrosphere.entity.state.inventory.ClientInventoryState;
import electrosphere.entity.state.inventory.InventoryUtils;
@ -169,32 +164,8 @@ public class CommonEntityUtils {
//
if(rawType.getGraphicsTemplate() != null){
GraphicsTemplate graphicsTemplate = rawType.getGraphicsTemplate();
if(graphicsTemplate.getModel() != null && graphicsTemplate.getModel().getPath() != null && EntityUtils.getActor(entity) == null && generateDrawable == true){
EntityCreationUtils.makeEntityDrawable(entity, graphicsTemplate.getModel().getPath());
}
//idle tree & generic stuff all entities have
if(graphicsTemplate.getModel() != null && graphicsTemplate.getModel().getIdleData() != null){
ClientIdleTree.attachTree(entity, graphicsTemplate.getModel().getIdleData());
}
if(graphicsTemplate.getModel() != null && graphicsTemplate.getModel().getUniforms() != null){
Actor creatureActor = EntityUtils.getActor(entity);
Map<String,Map<String,Object>> meshUniformMap = graphicsTemplate.getModel().getUniforms();
Set<String> meshNames = meshUniformMap.keySet();
for(String meshName : meshNames){
Map<String,Object> uniforms = meshUniformMap.get(meshName);
Set<String> uniformNames = uniforms.keySet();
for(String uniformName : uniformNames){
Object value = uniforms.get(uniformName);
creatureActor.setUniformOnMesh(meshName, uniformName, value);
}
}
}
if(graphicsTemplate.getModel() != null && graphicsTemplate.getModel().getMeshColorMap() != null){
Actor creatureActor = EntityUtils.getActor(entity);
Map<String,Vector3f> meshColorMap = graphicsTemplate.getModel().getMeshColorMap();
for(Entry<String,Vector3f> entry : meshColorMap.entrySet()){
creatureActor.setUniformOnMesh(entry.getKey(), "color", entry.getValue());
}
if(graphicsTemplate.getModel() != null && EntityUtils.getActor(entity) == null && generateDrawable == true){
DrawableUtils.applyNonproceduralModel(entity, graphicsTemplate.getModel());
}
}
Actor creatureActor = EntityUtils.getActor(entity);

View File

@ -44,11 +44,32 @@ public class Actor {
*/
public static final int INVALID_ANIMATION = -1;
/**
* full-resolution lod level
*/
public static final int LOD_LEVEL_FULL = 1;
/**
* lower-resolution lod level
*/
public static final int LOD_LEVEL_LOWER = 0;
/**
* the model path of the model backing the actor
*/
private String modelPath;
/**
* Path to the low res model
*/
private String lowResPath;
/**
* The LOD level of the actor
*/
private int lodLevel = Actor.LOD_LEVEL_FULL;
/**
* used for statically binding textures in pipelines that dont bind textures on a per-mesh level
* ie when in the ui, this can be set to bind a texture at the actor level
@ -124,6 +145,16 @@ public class Actor {
* Sets scaling applied at the actor level
*/
private float scale = 1.0f;
/**
* The transform matrix
*/
private Matrix4d modelMatrix = new Matrix4d();
/**
* The world position vector
*/
private Vector3d worldPos = new Vector3d();
/**
* Creates an achor
@ -438,7 +469,7 @@ public class Actor {
* Calculates the node transforms for the actor
* @param model The model that backs the actor
*/
void calculateNodeTransforms(Model model){
private void calculateNodeTransforms(Model model){
model.updateNodeTransform(boneRotators,staticMorph);
for(Bone bone : model.getBones()){
//store position
@ -478,8 +509,8 @@ public class Actor {
public void applySpatialData(Matrix4d modelMatrix, Vector3d worldPos){
Model model = Globals.assetManager.fetchModel(modelPath);
if(model != null){
model.setModelMatrix(modelMatrix);
model.setWorldPos(worldPos);
this.modelMatrix.set(modelMatrix);
this.worldPos.set(worldPos);
}
}
@ -489,14 +520,29 @@ public class Actor {
*/
public void draw(RenderPipelineState renderPipelineState, OpenGLState openGLState){
Globals.profiler.beginAggregateCpuSample("Actor.draw");
Model model = Globals.assetManager.fetchModel(modelPath);
if(model != null && Actor.isWithinFrustumBox(renderPipelineState,model,frustumCull)){
//fetch the model
String pathToFetch = this.modelPath;
if(this.lodLevel == Actor.LOD_LEVEL_LOWER && this.lowResPath != null){
pathToFetch = this.lowResPath;
}
Model model = Globals.assetManager.fetchModel(pathToFetch);
if(model == null){
Globals.profiler.endCpuSample();
return;
}
model.setModelMatrix(this.modelMatrix);
model.setWorldPos(this.worldPos);
//frustum cull then draw
if(Actor.isWithinFrustumBox(renderPipelineState,model,frustumCull)){
this.applyAnimationMasks(model);
meshMask.processMeshMaskQueue();
model.setMeshMask(meshMask);
model.setTextureMask(textureMap);
for(ActorShaderMask shaderMask : shaderMasks){
if(shaderMask.getModelName().equals(modelPath)){
if(shaderMask.getModelName().equals(pathToFetch)){
model.getShaderMask().put(shaderMask.getMeshName(),shaderMask);
}
}
@ -534,13 +580,18 @@ public class Actor {
*/
public boolean isStaticDrawCall(){
return
this.animationQueue.size() == 0 &&
this.meshMask.getBlockedMeshes().size() == 0 &&
this.textureMap == null &&
this.shaderMasks.size() == 0 &&
this.textureOverride == null &&
this.uniformMap.isEmpty() &&
this.staticMorph == null
//is low lod level
this.lodLevel == Actor.LOD_LEVEL_LOWER ||
//actor doesn't have anything complicated render-wise (animations, custom textures, etc)
(
this.animationQueue.size() == 0 &&
this.meshMask.getBlockedMeshes().size() == 0 &&
this.textureMap == null &&
this.shaderMasks.size() == 0 &&
this.textureOverride == null &&
this.uniformMap.isEmpty() &&
this.staticMorph == null
)
;
}
@ -873,4 +924,37 @@ public class Actor {
this.scale = scale;
}
/**
* Gets the path to the low res model
* @return Path to the low res model
*/
public String getLowResPath() {
return lowResPath;
}
/**
* Sets the path to the low res model
* @param lowResPath The path to the low res model
*/
public void setLowResPath(String lowResPath) {
this.lowResPath = lowResPath;
}
/**
* Gets the lod level
* @return The lod level
*/
public int getLodLevel(){
return this.lodLevel;
}
/**
* Sets the lod level of the actor
* @param lodLevel The lod level
*/
public void setLodLevel(int lodLevel){
this.lodLevel = lodLevel;
}
}

View File

@ -19,6 +19,12 @@ import electrosphere.renderer.pipelines.MainContentPipeline;
* Evaluates the draw targets
*/
public class DrawTargetEvaluator {
/**
* Cutoff after which we start using LOD models
*/
public static final int LOD_CUTOFF = 100;
/**
* Evaluates the draw targets
@ -54,6 +60,19 @@ public class DrawTargetEvaluator {
Vector3d position = EntityUtils.getPosition(currentEntity);
//fetch actor
Actor currentActor = EntityUtils.getActor(currentEntity);
//evaluate LOD level
if(currentActor.getLowResPath() != null){
posVec.set(position);
double dist = posVec.distance(cameraCenter);
if(dist < LOD_CUTOFF){
currentActor.setLodLevel(Actor.LOD_LEVEL_FULL);
} else {
currentActor.setLodLevel(Actor.LOD_LEVEL_LOWER);
}
}
//queue calls accordingly
if(!DrawableUtils.hasUniqueModel(currentEntity) && currentActor.isStaticDrawCall()){
//calculate camera-modified vector3d
Vector3d cameraModifiedPosition = positionVec.set(position).sub(cameraCenter);