Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Model caching #98

Merged
merged 4 commits into from
Aug 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions commons/src/main/com/mbrlabs/mundus/commons/Scene.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import com.mbrlabs.mundus.commons.env.CameraSettings;
import com.mbrlabs.mundus.commons.env.MundusEnvironment;
import com.mbrlabs.mundus.commons.env.lights.DirectionalLight;
import com.mbrlabs.mundus.commons.scene3d.ModelCacheManager;
import com.mbrlabs.mundus.commons.scene3d.SceneGraph;
import com.mbrlabs.mundus.commons.shaders.DepthShader;
import com.mbrlabs.mundus.commons.shaders.ShadowMapShader;
Expand Down Expand Up @@ -66,6 +67,7 @@ public class Scene implements Disposable {
public PerspectiveCamera cam;
public ModelBatch batch;
public ModelBatch depthBatch;
public ModelCacheManager modelCacheManager;

protected FrameBuffer fboWaterReflection;
protected FrameBuffer fboWaterRefraction;
Expand Down Expand Up @@ -95,6 +97,7 @@ public Scene() {
public Scene(boolean hasGLContext) {
environment = new MundusEnvironment();
settings = new SceneSettings();
modelCacheManager = new ModelCacheManager(this);

cam = new PerspectiveCamera(CameraSettings.DEFAULT_FOV, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
cam.position.set(0, 1, -3);
Expand Down Expand Up @@ -147,6 +150,8 @@ public void render(float delta) {
initFrameBuffers((int) res.x, (int) res.y);
}

modelCacheManager.update(delta);

if (sceneGraph.isContainsWater()) {
captureDepth(delta);
captureReflectionFBO(delta);
Expand All @@ -163,6 +168,7 @@ private void renderObjects(float delta) {
// Render objects
batch.begin(cam);
sceneGraph.render(delta, clippingPlaneDisable, 0);
batch.render(modelCacheManager.modelCache, environment);
batch.end();
}

Expand Down Expand Up @@ -196,6 +202,7 @@ private void renderShadowMap(float delta) {
shadowMapper.begin(light.direction);
depthBatch.begin(shadowMapper.getCam());
sceneGraph.renderDepth(delta, clippingPlaneDisable, 0, shadowMapShader);
depthBatch.render(modelCacheManager.modelCache, environment, shadowMapShader);
depthBatch.end();
shadowMapper.end();
}
Expand Down Expand Up @@ -225,6 +232,7 @@ private void captureReflectionFBO(float delta) {
renderSkybox();
batch.begin(cam);
sceneGraph.render(delta, clippingPlaneReflection, -settings.waterHeight + settings.distortionEdgeCorrection);
batch.render(modelCacheManager.modelCache, environment);
batch.end();
fboWaterReflection.end();

Expand All @@ -240,6 +248,7 @@ private void captureDepth(float delta) {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
depthBatch.begin(cam);
sceneGraph.renderDepth(delta, clippingPlaneRefraction, settings.waterHeight + settings.distortionEdgeCorrection, depthShader);
depthBatch.render(modelCacheManager.modelCache, environment, depthShader);
depthBatch.end();
fboDepthRefraction.end();
}
Expand All @@ -259,6 +268,7 @@ private void captureRefractionFBO(float delta) {
renderSkybox();
batch.begin(cam);
sceneGraph.render(delta, clippingPlaneRefraction, settings.waterHeight + settings.distortionEdgeCorrection);
batch.render(modelCacheManager.modelCache, environment);
batch.end();
fboWaterRefraction.end();
}
Expand Down Expand Up @@ -357,5 +367,6 @@ public void dispose() {
if (skybox != null) {
skybox.dispose();
}
modelCacheManager.dispose();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public class ModelComponentDTO {

private String modelID;
private HashMap<String, String> materials; // g3db material id to material asset uuid
private boolean useModelCache;

public ModelComponentDTO() {
materials = new HashMap<>();
Expand All @@ -47,4 +48,11 @@ public void setModelID(String modelID) {
this.modelID = modelID;
}

public boolean isUseModelCache() {
return useModelCache;
}

public void setUseModelCache(boolean useModelCache) {
this.useModelCache = useModelCache;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package com.mbrlabs.mundus.commons.scene3d;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Mesh;
import com.badlogic.gdx.graphics.g3d.ModelCache;
import com.badlogic.gdx.graphics.g3d.ModelInstance;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Disposable;
import com.mbrlabs.mundus.commons.Scene;
import com.mbrlabs.mundus.commons.scene3d.components.Component;

/**
* Manages a ModelCache and keeps it up to date based on requests for rebuilds and set intervals
*
* @author JamesTKhan
* @version August 02, 2022
*/
public class ModelCacheManager implements Disposable {
private final Scene scene;

public ModelCache modelCache;
protected float modelCacheUpdateInterval = 0.5f;
protected float lastModelCacheRebuild = modelCacheUpdateInterval;
protected boolean modelCacheRebuildRequested = true;

public ModelCacheManager(Scene scene) {
modelCache = new ModelCache();
this.scene = scene;
}

public void update(float delta) {
if (modelCacheRebuildRequested) {
lastModelCacheRebuild += delta;

if (lastModelCacheRebuild > modelCacheUpdateInterval) {
modelCacheRebuildRequested = false;
lastModelCacheRebuild = 0f;
rebuildModelCache();
}
}
}

/**
* Rebuilds model cache for the current scene. Potentially expensive
* depending on the size of the scene and should only be rebuilt when needed.
*/
public void rebuildModelCache() {
modelCache.begin(scene.cam);
addModelsToCache(scene.sceneGraph.getGameObjects());
modelCache.end();
}

protected void addModelsToCache(Array<GameObject> gameObjects) {
for (GameObject go : gameObjects) {

if (!go.active) continue;

for (Component comp : go.getComponents()) {
if (comp instanceof ModelCacheable && ((ModelCacheable) comp).shouldCache()) {
ModelInstance modelInstance = ((ModelCacheable) comp).getModelInstance();

boolean skip = false;
for (Mesh mesh : modelInstance.model.meshes) {
if (mesh.getNumIndices() <= 0) {
Gdx.app.error(this.getClass().getSimpleName(), "Issues in mesh for " + go.name + " prevent it from being cacheable. Try cleaning mesh up in 3D modeling software.");
skip = true;
break;
}
}
if (skip) {
continue;
}

modelCache.add(((ModelCacheable) comp).getModelInstance());
}
}

if (go.getChildren() != null) {
addModelsToCache(go.getChildren());
}
}
}

/**
* Request for the model cache to be rebuilt on the next interval
*/
public void requestModelCacheRebuild() {
modelCacheRebuildRequested = true;
}

/**
* Change how often the model cache should be updated, in seconds.
*
* @param interval update interval
*/
public void setModelCacheUpdateInterval(float interval) {
modelCacheUpdateInterval = interval;
}

/**
* Rebuild model cache if given GameObject has a cacheable component.
*/
public static void rebuildIfCached(GameObject go, boolean immediately) {
for (int i = 0; i < go.getComponents().size; i++) {
if (go.getComponents().get(i) instanceof ModelCacheable) {
if (immediately)
go.sceneGraph.scene.modelCacheManager.rebuildModelCache();
else
go.sceneGraph.scene.modelCacheManager.requestModelCacheRebuild();
break;
}
}
}

@Override
public void dispose() {
modelCache.dispose();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.mbrlabs.mundus.commons.scene3d;

import com.badlogic.gdx.graphics.g3d.ModelInstance;

/**
* Indicates the object has a ModelInstance that can be cached.
*
* @author JamesTKhan
* @version August 02, 2022
*/
public interface ModelCacheable {

/**
* Should this be used in a model cache
*/
boolean shouldCache();

/**
* Sets if this should use a model cache or not
*/
void setUseModelCache(boolean value);

/**
* Returns the model instance for model caching
*/
ModelInstance getModelInstance();
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.badlogic.gdx.math.collision.BoundingBox;
import com.mbrlabs.mundus.commons.env.lights.DirectionalLight;
import com.mbrlabs.mundus.commons.scene3d.GameObject;
import com.mbrlabs.mundus.commons.scene3d.ModelCacheable;
import com.mbrlabs.mundus.commons.shadows.ShadowMapper;
import com.mbrlabs.mundus.commons.utils.LightUtils;

Expand Down Expand Up @@ -68,6 +69,13 @@ public void render(float delta) {
return;
}

// Cannot frustum cull model cache objects, no reason for perform calculations
if (this instanceof ModelCacheable) {
if (((ModelCacheable) this).shouldCache()) {
isCulled = false;
}
}

boolean visibleToPerspective;
boolean visibleToShadowMap = false;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.mbrlabs.mundus.commons.assets.ModelAsset;
import com.mbrlabs.mundus.commons.assets.TextureAsset;
import com.mbrlabs.mundus.commons.scene3d.GameObject;
import com.mbrlabs.mundus.commons.scene3d.ModelCacheable;
import com.mbrlabs.mundus.commons.shaders.ClippableShader;
import com.mbrlabs.mundus.commons.shaders.ShadowMapShader;

Expand All @@ -35,11 +36,12 @@
* @author Marcus Brummer
* @version 17-01-2016
*/
public class ModelComponent extends CullableComponent implements AssetUsage, ClippableComponent {
public class ModelComponent extends CullableComponent implements AssetUsage, ClippableComponent, ModelCacheable {

protected ModelAsset modelAsset;
protected ModelInstance modelInstance;
protected Shader shader;
protected boolean useModelCache = false;

protected ObjectMap<String, MaterialAsset> materials; // g3db material id to material asset uuid

Expand Down Expand Up @@ -97,6 +99,17 @@ public void applyMaterials() {
}
}

@Override
public boolean shouldCache() {
return useModelCache;
}

@Override
public void setUseModelCache(boolean value) {
useModelCache = value;
}

@Override
public ModelInstance getModelInstance() {
return modelInstance;
}
Expand All @@ -108,7 +121,7 @@ public void render(float delta) {

super.render(delta);

if (isCulled) return;
if (isCulled || useModelCache) return;

if (shader != null) {
gameObject.sceneGraph.scene.batch.render(modelInstance, gameObject.sceneGraph.scene.environment, shader);
Expand All @@ -119,7 +132,7 @@ public void render(float delta) {

@Override
public void renderDepth(float delta, Vector3 clippingPlane, float clipHeight, Shader depthShader) {
if (isCulled) return;
if (isCulled || useModelCache) return;

if (depthShader instanceof ClippableShader) {
((ClippableShader) depthShader).setClippingPlane(clippingPlane);
Expand Down Expand Up @@ -157,6 +170,8 @@ public Component clone(GameObject go) {
mc.shader = this.shader;
mc.materials = this.materials;
mc.setDimensions(mc.modelInstance);
mc.setUseModelCache(useModelCache);
gameObject.sceneGraph.scene.modelCacheManager.requestModelCacheRebuild();
return mc;
}

Expand Down
9 changes: 8 additions & 1 deletion editor/src/main/com/mbrlabs/mundus/editor/Editor.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import com.mbrlabs.mundus.editor.core.project.ProjectManager
import com.mbrlabs.mundus.editor.core.registry.Registry
import com.mbrlabs.mundus.editor.events.FilesDroppedEvent
import com.mbrlabs.mundus.editor.events.FullScreenEvent
import com.mbrlabs.mundus.editor.events.GameObjectModifiedEvent
import com.mbrlabs.mundus.editor.events.ProjectChangedEvent
import com.mbrlabs.mundus.editor.events.SceneChangedEvent
import com.mbrlabs.mundus.editor.input.FreeCamController
Expand All @@ -59,7 +60,8 @@ import org.lwjgl.opengl.GL11
class Editor : Lwjgl3WindowAdapter(), ApplicationListener,
ProjectChangedEvent.ProjectChangedListener,
SceneChangedEvent.SceneChangedListener,
FullScreenEvent.FullScreenEventListener {
FullScreenEvent.FullScreenEventListener,
GameObjectModifiedEvent.GameObjectModifiedListener {

private lateinit var axesInstance: ModelInstance
private lateinit var compass: Compass
Expand Down Expand Up @@ -251,6 +253,11 @@ class Editor : Lwjgl3WindowAdapter(), ApplicationListener,
Mundus.postEvent(FilesDroppedEvent(files))
}

override fun onGameObjectModified(event: GameObjectModifiedEvent) {
if (event.gameObject == null) return
projectManager.current().currScene.modelCacheManager.requestModelCacheRebuild()
}

override fun dispose() {
debugRenderer.dispose()
Mundus.dispose()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import com.mbrlabs.mundus.commons.dto.ModelComponentDTO;
import com.mbrlabs.mundus.commons.scene3d.GameObject;
import com.mbrlabs.mundus.editor.scene3d.components.PickableModelComponent;
import com.mbrlabs.mundus.editor.shader.Shaders;
import com.mbrlabs.mundus.editor.utils.Log;

import java.util.Map;
Expand All @@ -48,6 +47,7 @@ public static PickableModelComponent convert(ModelComponentDTO dto, GameObject g

PickableModelComponent component = new PickableModelComponent(go);
component.setModel(model, false);
component.setUseModelCache(dto.isUseModelCache());

for (String g3dbMatID : dto.getMaterials().keySet()) {
String uuid = dto.getMaterials().get(g3dbMatID);
Expand All @@ -64,6 +64,7 @@ public static PickableModelComponent convert(ModelComponentDTO dto, GameObject g
public static ModelComponentDTO convert(PickableModelComponent modelComponent) {
ModelComponentDTO dto = new ModelComponentDTO();
dto.setModelID(modelComponent.getModelAsset().getID());
dto.setUseModelCache(modelComponent.shouldCache());

// materials
for (String g3dbMatID : modelComponent.getMaterials().keys()) {
Expand Down
Loading