Proper frustum culling
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2024-02-29 19:14:17 -05:00
parent 1883ffddf3
commit 5356b3e325
24 changed files with 303 additions and 81 deletions

View File

@ -1,3 +1,3 @@
#maven.buildNumber.plugin properties file
#Thu Feb 29 11:18:06 EST 2024
buildNumber=29
#Thu Feb 29 18:57:13 EST 2024
buildNumber=30

View File

@ -0,0 +1,9 @@
@page actorsindex Actors
[TOC]
- @subpage texturemask
- @subpage bonerotators
- @subpage staticmorph
- @subpage shadermask
- @subpage animationmask
- @subpage meshmask

View File

@ -0,0 +1,5 @@
@page animationmask Animation Mask
TODO
use example: play running animation for whole actor, but then mask crafting animation on top of bones from torso up

View File

@ -0,0 +1,5 @@
@page bonerotators Actor Bone Rotators
TODO
use example: rotate torso to tilt based on whatever the player is locked on to, so that they swing at goblins below them and harpies above them

View File

@ -0,0 +1,5 @@
@page meshmask Mesh Mask
TODO
use example: overwriting a mesh without clothing to one with clothing

View File

@ -0,0 +1,5 @@
@page shadermask Shader Mask
TODO
use example: override default cube shader to use a shader that does raymarching

View File

@ -0,0 +1,5 @@
@page staticmorph Actor Static Morph
TODO
use example: scale something that was exported from blender waayyyyyy too large

View File

@ -0,0 +1,3 @@
@page texturemask Actor Texture Mask
TODO

View File

@ -90,7 +90,7 @@ public class FoliageCell {
instancedActor.setPriority((int)grassPosition.distance(playerPosition));
//draw
instancedActor.draw(Globals.renderingEngine.getRenderPipelineState());
instancedActor.draw(Globals.renderingEngine.getRenderPipelineState(), new Vector3d(cameraModifiedPosition));
}
}
}

View File

@ -0,0 +1,29 @@
package electrosphere.client.instancing;
import org.joml.Vector3d;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityTags;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.types.camera.CameraEntityUtils;
import electrosphere.renderer.actor.instance.InstancedActor;
/**
* Used for updating instance priority
*/
public class InstanceUpdater {
/**
* Updates all instanced actors to have priority based on distance from camera
*/
public static void updateInstancedActorPriority(){
Vector3d eyePosition = new Vector3d(CameraEntityUtils.getCameraEye(Globals.playerCamera));
for(Entity entity : Globals.clientScene.getEntitiesWithTag(EntityTags.DRAW_INSTANCED)){
//set priority equal to distance
Vector3d entityPosition = EntityUtils.getPosition(entity);
InstancedActor.getInstancedActor(entity).setPriority((int)entityPosition.distance(eyePosition));
}
}
}

View File

@ -1,5 +1,6 @@
package electrosphere.client.sim;
import electrosphere.client.instancing.InstanceUpdater;
import electrosphere.client.terrain.manager.ClientTerrainManager;
import electrosphere.engine.Globals;
import electrosphere.entity.EntityUtils;
@ -28,6 +29,7 @@ public class ClientFunctions {
ClientTerrainManager.generateTerrainChunkGeometry();
updateSkyboxPos();
Globals.clientSceneWrapper.destroyEntitiesOutsideSimRange();
InstanceUpdater.updateInstancedActorPriority();
// updateCellManager();
}

View File

@ -74,10 +74,6 @@ public class ClientSimulation {
}
//clear collidable impulse lists
Globals.clientSceneWrapper.getCollisionEngine().clearCollidableImpulseLists();
//delete all client side entities that aren't in visible chunks
if(Globals.clientEntityCullingManager != null){
Globals.clientEntityCullingManager.clearOutOfBoundsEntities();
}
}
/**

View File

@ -23,7 +23,7 @@ import electrosphere.entity.types.terrain.TerrainChunkData;
public class CollisionBodyCreation {
//Matrix for correcting initial axis of eg cylinders or capsules
static final DMatrix3 AXIS_CORRECTION_MATRIX = new DMatrix3(
public static final DMatrix3 AXIS_CORRECTION_MATRIX = new DMatrix3(
1.0000000, 0.0000000, 0.0000000,
0.0000000, 0.0000000, -1.0000000,
0.0000000, 1.0000000, 0.0000000
@ -65,7 +65,7 @@ public class CollisionBodyCreation {
public static DBody createCylinderBody(CollisionEngine collisionEngine, double radius, double length){
DCylinder geom = collisionEngine.createCylinderGeom(radius,length);
DBody returnBody = collisionEngine.createDBody(geom);
geom.setOffsetRotation(AXIS_CORRECTION_MATRIX); //ode4j required geom to already be on body before rotating for some reason
collisionEngine.setOffsetRotation(geom); //ode4j required geom to already be on body before rotating for some reason
return returnBody;
}

View File

@ -671,6 +671,16 @@ public class CollisionEngine {
spaceLock.release();
}
/**
* Corrects the initial axis of eg cylinders or capsules
* @param geom the geometry to correct
*/
protected void setOffsetRotation(DGeom geom){
spaceLock.acquireUninterruptibly();
geom.setOffsetRotation(CollisionBodyCreation.AXIS_CORRECTION_MATRIX);
spaceLock.release();
}
/**
* Gets the position of the body in a thread-safe way
* @param body The body to get the position of

View File

@ -25,6 +25,7 @@ import java.util.Map;
import org.joml.Matrix4d;
import org.joml.Matrix4f;
import org.joml.Quaternionf;
import org.joml.Sphered;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.joml.Vector4d;
@ -114,6 +115,9 @@ public class Mesh {
Material material;
//the bounding sphere for this mesh
Sphered boundingSphere;
public static Mesh create_mesh_from_aimesh(AIMesh mesh, ModelPretransforms.MeshMetadata metadata){
boolean has_bones = false;
boolean apply_lighting = true;
@ -184,6 +188,7 @@ public class Mesh {
float x = vertex.x();
float y = vertex.y();
float z = vertex.z();
//store dimensions of the model
if(definedDimensions){
if(x < minX){ minX = x; }
if(x > maxX){ maxX = x; }
@ -197,6 +202,12 @@ public class Mesh {
minY = maxY = y;
minZ = maxZ = z;
}
//update bounding sphere
double dist = Math.sqrt(x*x+y*y+z*z);
if(dist > rVal.boundingSphere.r){
rVal.boundingSphere.r = dist;
}
//store vertex data
Vector4d transformedVertex = vertexPretransform.transform(new Vector4d(x,y,z,1.0));
transformedVertex.w = 1.0;
temp[0] = (float)transformedVertex.x;
@ -456,7 +467,7 @@ public class Mesh {
public Mesh(){
this.boundingSphere = new Sphered();
}
@ -745,4 +756,26 @@ public class Mesh {
}
glBindVertexArray(0);
}
/**
* Updates the bounding sphere of the mesh
* @param x
* @param y
* @param z
* @param r
*/
public void updateBoundingSphere(float x, float y, float z, float r){
this.boundingSphere.x = x;
this.boundingSphere.y = y;
this.boundingSphere.z = z;
this.boundingSphere.r = r;
}
/**
* Gets the bounding sphere of this mesh
* @return The bounding sphere
*/
public Sphered getBoundingSphere(){
return this.boundingSphere;
}
}

View File

@ -44,6 +44,7 @@ import java.util.LinkedList;
import java.util.Map;
import java.util.Stack;
import org.joml.Quaternionf;
import org.joml.Sphered;
import org.joml.Vector3d;
import org.lwjgl.assimp.AIAnimation;
import org.lwjgl.assimp.AIBone;
@ -72,6 +73,15 @@ public class Model {
Map<String,ActorShaderMask> shaderMask = new HashMap<String,ActorShaderMask>();
Map<String,ActorTextureMask> textureMap = null;
//The bounding sphere for this particular model
Sphered boundingSphere;
/**
* Loads a model from an ai scene object
* @param path The path of the model
* @param s the ai scene
* @return The model object
*/
public static Model createModelFromAiscene(String path, AIScene s){
Model rVal = new Model();
//
@ -100,6 +110,10 @@ public class Model {
Mesh currentMesh = Mesh.create_mesh_from_aimesh(aiMesh, meshMetadata);
rVal.meshes.add(currentMesh);
currentMesh.parent = rVal;
//update model bounding sphere
if(currentMesh.boundingSphere.r > rVal.boundingSphere.r){
rVal.boundingSphere.r = currentMesh.boundingSphere.r;
}
}
//
//register bones
@ -211,6 +225,7 @@ public class Model {
modelMatrix = new Matrix4d();
program = null;
globalInverseTransform = null;
this.boundingSphere = new Sphered();
}
public void free() {
@ -532,4 +547,20 @@ public class Model {
mesh.setMaterial(material);
}
}
/**
* Gets the bounding sphere for this model
* @return The bounding sphere
*/
public Sphered getBoundingSphere(){
return boundingSphere;
}
/**
* Sets the bounding sphere
* @param boundingSphere The bounding sphere to be stored
*/
public void setBoundingSphere(Sphered boundingSphere){
this.boundingSphere = boundingSphere;
}
}

View File

@ -1,5 +1,8 @@
package electrosphere.renderer;
import org.joml.FrustumIntersection;
import org.joml.Matrix4f;
import electrosphere.renderer.actor.instance.InstanceData;
/**
@ -53,6 +56,9 @@ public class RenderPipelineState {
//The pointer to the current shader program bound
int currentShaderPointer;
//JOML-provided object to perform frustum culling
FrustumIntersection frustumInt = new FrustumIntersection();
public boolean getUseMeshShader(){
return this.useMeshShader;
}
@ -141,4 +147,24 @@ public class RenderPipelineState {
this.currentShaderPointer = currentShaderPointer;
}
/**
* Updates the frustum intersection with the provided projection and view matrices
* @param projectionMatrix the projection matrix
* @param viewMatrix the view matrix
*/
public void updateFrustumIntersection(Matrix4f projectionMatrix, Matrix4f viewMatrix){
Matrix4f projectionViewMatrix = new Matrix4f();
projectionViewMatrix.set(projectionMatrix);
projectionViewMatrix.mul(viewMatrix);
this.frustumInt.set(projectionViewMatrix);
}
/**
* Gets the current render pipeline's frustum intersection object
* @return The frustum intersection object
*/
public FrustumIntersection getFrustumIntersection(){
return frustumInt;
}
}

View File

@ -65,6 +65,7 @@ import org.joml.Matrix4d;
import org.joml.Matrix4f;
import org.joml.Quaterniond;
import org.joml.Quaternionf;
import org.joml.Sphered;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.lwjgl.BufferUtils;
@ -182,8 +183,6 @@ public class RenderingEngine {
LightManager lightManager;
static float currentViewPlanarAngle;
ShaderProgram activeProgram;
static int outputFramebuffer = 0;
@ -192,6 +191,7 @@ public class RenderingEngine {
static float aspectRatio = 1.0f;
static float verticalFOV = 90.0f;
//the current state of the rendering pipeline
static RenderPipelineState renderPipelineState = new RenderPipelineState();
@ -409,32 +409,22 @@ public class RenderingEngine {
return origin.distance(target);
}
static boolean drawPoint(Vector3f cameraPos, Vector3f position){
boolean rVal = true;
float phi = (float)Math.abs((calculateAngle(cameraPos,position) - currentViewPlanarAngle) % (Math.PI * 2.0f));
if(phi > Math.PI){
phi = (float)(Math.PI * 2) - phi;
}
float rotationalDiff = phi;
float dist = calculateDist(new Vector3f(cameraPos.x,0,cameraPos.z), new Vector3f(position.x,0,position.z));
if(rotationalDiff > (Globals.verticalFOV / 180 * Math.PI) && dist > 300){
rVal = false;
}
return rVal;
}
void calculateRenderingAngle(){
currentViewPlanarAngle = calculateAngle(CameraEntityUtils.getCameraEye(Globals.playerCamera), new Vector3f(0,0,0));
// System.out.println(currentViewPlanarAngle);
/**
* Updates the frustum box of the render pipeline
*/
void updateFrustumBox(){
renderPipelineState.updateFrustumIntersection(Globals.projectionMatrix, Globals.viewMatrix);
}
/**
* Main function to draw the screen
*/
public void drawScreen(){
//calculate render angle for frustum culling
if(Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER_CONTENT){
calculateRenderingAngle();
updateFrustumBox();
}
//
@ -581,7 +571,6 @@ public class RenderingEngine {
Vector3d position = EntityUtils.getPosition(currentEntity);
if(
(boolean)currentEntity.getData(EntityDataStrings.DATA_STRING_DRAW) &&
drawPoint(cameraPos,new Vector3f((float)position.x,(float)position.y,(float)position.z)) &&
currentEntity.containsKey(EntityDataStrings.DRAW_CAST_SHADOW)
){
//fetch actor
@ -658,8 +647,7 @@ public class RenderingEngine {
Vector3d position = EntityUtils.getPosition(currentEntity);
if(
(boolean)currentEntity.getData(EntityDataStrings.DATA_STRING_DRAW) &&
currentEntity.getData(EntityDataStrings.DRAW_SOLID_PASS) != null &&
drawPoint(cameraPos,new Vector3f((float)position.x,(float)position.y,(float)position.z))
currentEntity.getData(EntityDataStrings.DRAW_SOLID_PASS) != null
){
//fetch actor
Actor currentActor = EntityUtils.getActor(currentEntity);
@ -679,8 +667,7 @@ public class RenderingEngine {
Vector3d position = EntityUtils.getPosition(currentEntity);
if(
currentEntity.getData(EntityDataStrings.DATA_STRING_DRAW) != null &&
currentEntity.getData(EntityDataStrings.DRAW_SOLID_PASS) != null &&
drawPoint(cameraPos,new Vector3f((float)position.x,(float)position.y,(float)position.z))
currentEntity.getData(EntityDataStrings.DRAW_SOLID_PASS) != null
){
//fetch actor
InstancedActor currentActor = InstancedActor.getInstancedActor(currentEntity);
@ -696,15 +683,13 @@ public class RenderingEngine {
new Quaternionf((float)rotation.x,(float)rotation.y,(float)rotation.z,(float)rotation.w),
new Vector3f(EntityUtils.getScale(currentEntity))
);
// modelTransformMatrix.translate(cameraModifiedPosition);
// modelTransformMatrix.rotate(rotation);
// modelTransformMatrix.scale(new Vector3d(EntityUtils.getScale(currentEntity)));
//set actor value
currentActor.setAttribute(modelAttribute, new Matrix4f(modelTransformMatrix));
// ((Matrix4f)currentActor.getAttributeValue(modelAttribute)).set(modelTransformMatrix);
//draw
currentActor.draw(renderPipelineState, new Vector3d(cameraModifiedPosition));
} else {
currentActor.draw(renderPipelineState);
}
//draw
currentActor.draw(renderPipelineState);
}
}
//draw all instanced models
@ -747,8 +732,7 @@ public class RenderingEngine {
Vector3d position = EntityUtils.getPosition(currentEntity);
if(
(boolean)currentEntity.getData(EntityDataStrings.DATA_STRING_DRAW) &&
currentEntity.getData(EntityDataStrings.DRAW_TRANSPARENT_PASS) != null &&
drawPoint(cameraPos,new Vector3f((float)position.x,(float)position.y,(float)position.z))
currentEntity.getData(EntityDataStrings.DRAW_TRANSPARENT_PASS) != null
){
//fetch actor
Actor currentActor = EntityUtils.getActor(currentEntity);
@ -768,13 +752,27 @@ public class RenderingEngine {
Vector3d position = EntityUtils.getPosition(currentEntity);
if(
currentEntity.getData(EntityDataStrings.DATA_STRING_DRAW) != null &&
currentEntity.getData(EntityDataStrings.DRAW_TRANSPARENT_PASS) != null &&
drawPoint(cameraPos,new Vector3f((float)position.x,(float)position.y,(float)position.z))
currentEntity.getData(EntityDataStrings.DRAW_TRANSPARENT_PASS) != null
){
//fetch actor
InstancedActor currentActor = InstancedActor.getInstancedActor(currentEntity);
//draw
if(currentActor != null){
//if the shader attribute for model matrix exists, calculate the model matrix and apply
if(InstancedActor.getInstanceModelAttribute(currentEntity) != null){
ShaderAttribute modelAttribute = InstancedActor.getInstanceModelAttribute(currentEntity);
//calculate model matrix
Vector3f cameraModifiedPosition = new Vector3f((float)position.x,(float)position.y,(float)position.z).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera));
Quaterniond rotation = EntityUtils.getRotation(currentEntity);
// modelTransformMatrix.identity();
modelTransformMatrix.identity().translationRotateScale(
cameraModifiedPosition,
new Quaternionf((float)rotation.x,(float)rotation.y,(float)rotation.z,(float)rotation.w),
new Vector3f(EntityUtils.getScale(currentEntity))
);
//set actor value
currentActor.setAttribute(modelAttribute, new Matrix4f(modelTransformMatrix));
//draw
currentActor.draw(renderPipelineState, new Vector3d(cameraModifiedPosition));
} else {
currentActor.draw(renderPipelineState);
}
}
@ -833,8 +831,7 @@ public class RenderingEngine {
for(Entity currentEntity : Globals.clientScene.getEntitiesWithTag(EntityTags.DRAWABLE)){
Vector3d position = EntityUtils.getPosition(currentEntity);
if(
(boolean)currentEntity.getData(EntityDataStrings.DATA_STRING_DRAW) &&
drawPoint(cameraPos,new Vector3f((float)position.x,(float)position.y,(float)position.z))
(boolean)currentEntity.getData(EntityDataStrings.DATA_STRING_DRAW)
){
//fetch actor
Actor currentActor = EntityUtils.getActor(currentEntity);
@ -1080,8 +1077,7 @@ public class RenderingEngine {
if(
(boolean)currentEntity.getData(EntityDataStrings.DATA_STRING_DRAW) &&
currentEntity.getData(EntityDataStrings.DRAW_SOLID_PASS) != null &&
currentEntity.getData(EntityDataStrings.DRAW_OUTLINE) != null &&
drawPoint(cameraPos,new Vector3f((float)position.x,(float)position.y,(float)position.z))
currentEntity.getData(EntityDataStrings.DRAW_OUTLINE) != null
){
//fetch actor
Actor currentActor = EntityUtils.getActor(currentEntity);
@ -1334,7 +1330,6 @@ public class RenderingEngine {
Vector3d position = EntityUtils.getPosition(currentEntity);
if(
(boolean)currentEntity.getData(EntityDataStrings.DATA_STRING_DRAW) &&
drawPoint(cameraPos,new Vector3f((float)position.x,(float)position.y,(float)position.z)) &&
currentEntity.containsKey(EntityDataStrings.DRAW_VOLUMETRIC)
){
//fetch actor
@ -1372,7 +1367,6 @@ public class RenderingEngine {
Vector3d position = EntityUtils.getPosition(currentEntity);
if(
(boolean)currentEntity.getData(EntityDataStrings.DATA_STRING_DRAW) &&
drawPoint(cameraPos,new Vector3f((float)position.x,(float)position.y,(float)position.z)) &&
!currentEntity.containsKey(EntityDataStrings.DRAW_VOLUMETRIC)
){
//fetch actor
@ -1421,7 +1415,6 @@ public class RenderingEngine {
Vector3d position = EntityUtils.getPosition(currentEntity);
if(
(boolean)currentEntity.getData(EntityDataStrings.DATA_STRING_DRAW) &&
drawPoint(cameraPos,new Vector3f((float)position.x,(float)position.y,(float)position.z)) &&
currentEntity.containsKey(EntityDataStrings.DRAW_VOLUMETRIC)
){
//fetch actor

View File

@ -17,23 +17,50 @@ import org.joml.Matrix4d;
import org.joml.Matrix4f;
import org.joml.Quaterniond;
import org.joml.Quaternionf;
import org.joml.Sphered;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.joml.Vector4d;
import org.joml.Vector4f;
/**
*
* @author amaterasu
* An actor
* Container for a model that keeps track of:
* - Animation state
* - Mesh overrides
* - Shader overrides
* - Texture overrides
* - Bone overrides
* - Static Morphs (think scaling something, but from creatures.json)
*/
public class Actor {
//the model path of the model backing the actor
String modelPath;
//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
String textureOverride;
//scales the time that animations are played at
float animationScalar = 1.0f;
//The stack of animations being applied to a given actor
PriorityQueue<ActorAnimationMask> animationQueue = new PriorityQueue<ActorAnimationMask>();
//Mask for overwriting meshes in a given actor
ActorMeshMask meshMask = new ActorMeshMask();
//optional overrides for specific shaders
List<ActorShaderMask> shaderMasks = new LinkedList<ActorShaderMask>();
//optional overrides for textures
Map<String,ActorTextureMask> textureMap = null;
//bone rotators
Map<String,ActorBoneRotator> boneRotators = new HashMap<String,ActorBoneRotator>();
//static morph for this specific actor
ActorStaticMorph staticMorph;
public Actor(String modelPath){
@ -52,18 +79,6 @@ public class Actor {
for(ActorAnimationMask mask : toRemoveMasks){
animationQueue.remove(mask);
}
// if(playingAnimation){
// animationTime = animationTime + deltaTime * animationScalar;
// }
// if(model != null){
// if(animation != null){
// model.playAnimation(animation);
// model.incrementTime(animationTime);
// if(model.currentAnimation == null){
// playingAnimation = false;
// }
// }
// }
}
public double getAnimationTime(String animationName){
@ -100,10 +115,6 @@ public class Actor {
}
}
// public String getCurrentAnimation(){
// return animation;
// }
public void playAnimation(String animationName, int priority){
// animationTime = 0;
// playingAnimation = true;
@ -170,10 +181,6 @@ public class Actor {
model.updateNodeTransform(boneRotators,staticMorph);
}
// public boolean isPlayingAnimation(){
// return playingAnimation;
// }
public void setAnimationScalar(float animationScalar) {
this.animationScalar = animationScalar;
}
@ -185,10 +192,14 @@ public class Actor {
}
}
/**
* Draws an actor
* @param renderPipelineState The render pipeline state to draw within
*/
public void draw(RenderPipelineState renderPipelineState){
Model model = Globals.assetManager.fetchModel(modelPath);
boolean hasDrawn = false;
if(model != null){
if(model != null && isWithinFrustumBox(renderPipelineState,model)){
applyAnimationMasks(model);
meshMask.processMeshMaskQueue();
model.setMeshMask(meshMask);
@ -353,5 +364,17 @@ public class Actor {
return this.staticMorph;
}
/**
* Checks if a given model is within the render pipeline state's frustum box
* @param renderPipelineState The render pipeline state
* @param model The model
* @return true if it is within the box, false otherwise
*/
static boolean isWithinFrustumBox(RenderPipelineState renderPipelineState, Model model){
Sphered sphere = model.getBoundingSphere();
Vector3d modelPosition = model.modelMatrix.getTranslation(new Vector3d());
return renderPipelineState.getFrustumIntersection().testSphere((float)(sphere.x + modelPosition.x), (float)(sphere.y + modelPosition.y), (float)(sphere.z + modelPosition.z), (float)sphere.r);
}
}

View File

@ -2,6 +2,10 @@ package electrosphere.renderer.actor;
import org.joml.Quaternionf;
/**
* Optional rotation to be applied to a bone that can be programmatically controlled and applied alongside another animation.
* For instance, having a character look at something, turn their torso mid animation, or hair rotating around.
*/
public class ActorBoneRotator {
Quaternionf rotation = new Quaternionf().identity();

View File

@ -7,6 +7,10 @@ import org.joml.Matrix4f;
import org.joml.Quaternionf;
import org.joml.Vector3f;
/**
* A static morph that is applied to an actor if it is defined in a pipeline creating an actor.
* For instance, if you provide a static morph for the model in an item in creatures.json, this is the structure that will actually hold that data
*/
public class ActorStaticMorph {
Map<String,StaticMorphTransforms> boneTransformMap = new HashMap<String,StaticMorphTransforms>();

View File

@ -3,11 +3,15 @@ package electrosphere.renderer.actor.instance;
import java.nio.DoubleBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.NavigableSet;
import java.util.PriorityQueue;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentSkipListSet;
import org.joml.Matrix4d;
import org.joml.Matrix4f;
@ -37,8 +41,8 @@ public class InstanceData {
//the number of draw calls since the last clear operation
int drawCalls = 0;
//The priority queue of instanced actors to draw
PriorityQueue<InstancedActor> actorQueue = null;
//The set of instanced actors to draw
List<InstancedActor> actorQueue = null;
//Map of actor to index in the buffers that are emitted
Map<InstancedActor,Integer> actorIndexMap = new HashMap<InstancedActor,Integer>();
//Map of index -> actor used for buffer evictions
@ -60,7 +64,7 @@ public class InstanceData {
this.capacity = capacity;
this.vertexShaderPath = vertexPath;
this.fragmentShaderPath = fragmentPath;
actorQueue = new PriorityQueue<InstancedActor>(this.capacity);
actorQueue = new LinkedList<InstancedActor>();
}
/**
@ -179,6 +183,7 @@ public class InstanceData {
} break;
}
}
actorQueue.sort(Comparator.naturalOrder());
//buffer data
for(InstancedActor actor : actorQueue){
//push values to attribute buffers

View File

@ -6,11 +6,14 @@ import java.util.Map;
import org.joml.Matrix4d;
import org.joml.Matrix4f;
import org.joml.Sphered;
import org.joml.Vector3d;
import org.joml.Vector3f;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils;
import electrosphere.logger.LoggerInterface;
import electrosphere.renderer.Model;
import electrosphere.renderer.RenderPipelineState;
@ -41,6 +44,23 @@ public class InstancedActor implements Comparable<InstancedActor> {
/**
* Draws the instanced actor. Should be called normally in a loop as if this was a regular actor.
* @param renderPipelineState The pipeline state of the instanced actor
* @param position The position used for frustum checking
*/
public void draw(RenderPipelineState renderPipelineState, Vector3d position){
Model model = Globals.assetManager.fetchModel(modelPath);
if(model != null){
Sphered boundingSphere = model.getBoundingSphere();
//frustum check if the model matrix exists (and we therefore can get position)
boolean frustumCheck = renderPipelineState.getFrustumIntersection().testSphere((float)(position.x + boundingSphere.x), (float)(position.y + boundingSphere.y), (float)(position.z + boundingSphere.z), (float)boundingSphere.r);
if(frustumCheck){
Globals.clientInstanceManager.addToQueue(this);
}
}
}
/**
* Draws the instanced actor WITHOUT frustum checking. Otherwise identical to the call with frustum checking
* @param renderPipelineState
*/
public void draw(RenderPipelineState renderPipelineState){
Model model = Globals.assetManager.fetchModel(modelPath);

View File

@ -25,6 +25,7 @@ import electrosphere.renderer.Material;
import electrosphere.renderer.Mesh;
import electrosphere.renderer.Model;
import electrosphere.renderer.ShaderProgram;
import electrosphere.server.terrain.manager.ServerTerrainChunk;
public class TerrainChunkModelGeneration {
@ -775,6 +776,13 @@ public class TerrainChunkModelGeneration {
ex.printStackTrace();
}
float halfChunk = ServerTerrainChunk.CHUNK_DIMENSION / 2.0f;
mesh.updateBoundingSphere(
halfChunk,
halfChunk,
halfChunk,
(float)Math.sqrt(halfChunk * halfChunk + halfChunk * halfChunk + halfChunk * halfChunk)
);
@ -805,6 +813,7 @@ public class TerrainChunkModelGeneration {
m.parent = rVal;
rVal.meshes.add(m);
rVal.setBoundingSphere(m.getBoundingSphere());
return rVal;
}