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

Shadow Strategies and Variance Shadow Maps #259

Draft
wants to merge 13 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ allprojects {
mockitoVersion = '1.10.19'
commonsIoVersion = '2.5'
commonsLangVersion = '3.12.0'
gltfVersion = '2.1.0'
gltfVersion = '7d70839067'
args4jVersion = '2.33'

ktxVersion = '1.12.0-rc1'
Expand Down
128 changes: 128 additions & 0 deletions commons/src/main/com/mbrlabs/mundus/commons/rendering/BlurEffect.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package com.mbrlabs.mundus.commons.rendering;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.FrameBuffer;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
import com.badlogic.gdx.utils.Disposable;
import com.mbrlabs.mundus.commons.utils.NestableFrameBuffer;
import com.mbrlabs.mundus.commons.utils.ShaderUtils;

/**
* @author JamesTKhan
* @version October 07, 2023
*/
public class BlurEffect implements Disposable {
protected static final String VERTEX_SHADER = "com/mbrlabs/mundus/commons/shaders/postprocess/spritebatch.vert.glsl";
protected static final String FRAGMENT_SHADER = "com/mbrlabs/mundus/commons/shaders/postprocess/blur.frag.glsl";
private final SpriteBatch spriteBatch;
private FrameBuffer blurTargetA;
private FrameBuffer blurTargetB;
private ShaderProgram blurShader;

private int pingPongCount = 1;
private float maxBlur = 2f;

public BlurEffect(int width, int height, SpriteBatch spriteBatch) {
this.spriteBatch = spriteBatch;

blurShader = ShaderUtils.compile(VERTEX_SHADER, FRAGMENT_SHADER, null);

float blurScale = 1f;
blurTargetA = new NestableFrameBuffer(Pixmap.Format.RGBA8888, (int) (width * blurScale), (int) (height * blurScale), false);
blurTargetB = new NestableFrameBuffer(Pixmap.Format.RGBA8888, (int) (width * blurScale), (int) (height * blurScale), false);
}

public BlurEffect(int width, int height, SpriteBatch spriteBatch, int internalFormat, int format, int type) {
this.spriteBatch = spriteBatch;
blurShader = ShaderUtils.compile(VERTEX_SHADER, FRAGMENT_SHADER, null);
blurTargetA = buildFrameBuffer(width, height, internalFormat, format, type);
blurTargetB = buildFrameBuffer(width, height, internalFormat, format, type);
}

private FrameBuffer buildFrameBuffer(int width, int height, int internalFormat, int format, int type) {
NestableFrameBuffer.NestableFrameBufferBuilder builder = new NestableFrameBuffer.NestableFrameBufferBuilder(width, height);
builder.addColorTextureAttachment(internalFormat, format, type);
return builder.build();
}

public void setTextureFilter(Texture.TextureFilter minFilter, Texture.TextureFilter magFilter) {
blurTargetA.getColorBufferTexture().setFilter(minFilter, magFilter);
blurTargetB.getColorBufferTexture().setFilter(minFilter, magFilter);
}

public void setTextureWrap(Texture.TextureWrap uWrap, Texture.TextureWrap vWrap) {
blurTargetA.getColorBufferTexture().setWrap(uWrap, vWrap);
blurTargetB.getColorBufferTexture().setWrap(uWrap, vWrap);
}

public void process(FrameBuffer src, FrameBuffer dest) {
spriteBatch.setShader(blurShader);

float srcWidth = src.getWidth();
float srcHeight = src.getHeight();
spriteBatch.getProjectionMatrix().setToOrtho2D(0, 0, src.getWidth(), src.getHeight(), 0.0f, 1);

Gdx.gl.glDisable(GL20.GL_DEPTH_TEST);
Gdx.gl.glDepthMask(false);
spriteBatch.disableBlending();

for (int i = 0; i < pingPongCount; i++) {
// Horizontal blur pass
blurTargetA.begin();
spriteBatch.begin();
blurShader.setUniformf("dir", .5f, 0);
blurShader.setUniformf("radius", maxBlur);
blurShader.setUniformf("resolution", srcWidth);
spriteBatch.draw(i == 0 ? src.getColorBufferTexture() : blurTargetB.getColorBufferTexture(), 0, 0, srcWidth, srcHeight, 0, 0, 1, 1);
spriteBatch.end();
blurTargetA.end();

// Verticle blur pass
if (i == pingPongCount - 1) {
dest.begin();
} else {
blurTargetB.begin();
}
spriteBatch.begin();
blurShader.setUniformf("dir", 0, .5f);
blurShader.setUniformf("radius", maxBlur);
blurShader.setUniformf("resolution", srcHeight);
spriteBatch.draw(blurTargetA.getColorBufferTexture(), 0, 0, srcWidth, srcHeight, 0, 0, 1, 1);
spriteBatch.end();
if (i == pingPongCount - 1) {
dest.end();
} else {
blurTargetB.end();
}
}

spriteBatch.setShader(null);
}

public void setRadius(float radius) {
this.maxBlur = radius;
}

public float getRadius() {
return maxBlur;
}

public void setPingPongCount(int pingPongCount) {
this.pingPongCount = pingPongCount;
}

public int getPingPongCount() {
return pingPongCount;
}

@Override
public void dispose() {
blurTargetA.dispose();
blurTargetB.dispose();
blurShader.dispose();
}
}
Original file line number Diff line number Diff line change
@@ -1,34 +1,39 @@
package com.mbrlabs.mundus.commons.rendering;

import com.badlogic.gdx.graphics.g3d.Environment;
import com.badlogic.gdx.graphics.g3d.ModelBatch;
import com.badlogic.gdx.graphics.g3d.Shader;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.Disposable;
import com.mbrlabs.mundus.commons.Scene;
import com.mbrlabs.mundus.commons.shadows.strategy.ClassicShadowMap;
import com.mbrlabs.mundus.commons.shadows.strategy.ShadowMapStrategy;
import com.mbrlabs.mundus.commons.scene3d.GameObject;
import com.mbrlabs.mundus.commons.scene3d.ModelCacheable;
import com.mbrlabs.mundus.commons.scene3d.components.Component;
import com.mbrlabs.mundus.commons.scene3d.components.CullableComponent;
import com.mbrlabs.mundus.commons.scene3d.components.RenderableComponent;
import com.mbrlabs.mundus.commons.shadows.ShadowResolution;
import com.mbrlabs.mundus.commons.water.WaterResolution;

/**
* @author JamesTKhan
* @version October 03, 2023
*/
public class DefaultSceneRenderer implements SceneRenderer {
public class DefaultSceneRenderer implements SceneRenderer, Disposable {
public static final Vector3 clippingPlaneDisable = new Vector3(0.0f, 0f, 0.0f);
private WaterRenderer waterRenderer;
private final WaterRenderer waterRenderer;
private Shader depthShader;
private ShadowMapStrategy shadowMapStrategy;

public DefaultSceneRenderer() {
waterRenderer = new WaterRenderer();
shadowMapStrategy = new ClassicShadowMap();
}

@Override
public void render(Scene scene, float delta) {
waterRenderer.renderWaterFBOs(scene);
renderShadowMap(scene);
shadowMapStrategy.renderShadowMap(scene);
renderScene(scene, delta);
}

Expand Down Expand Up @@ -117,33 +122,6 @@ public void renderComponents(Scene scene, ModelBatch batch, GameObject parent, S
}
}

/**
* Render models to the shadow map .This is called by the render method normally, but if using post-processing
* you may want to call this method directly.
*/
public void renderShadowMap(Scene scene) {
if (scene.dirLight == null) {
scene.setShadowQuality(ShadowResolution.DEFAULT_SHADOW_RESOLUTION);
}

if (!scene.dirLight.isCastsShadows()) {
scene.environment.shadowMap = null;
return;
}

scene.environment.shadowMap = scene.dirLight;

scene.dirLight.setCenter(scene.cam.position);
scene.dirLight.begin();
scene.depthBatch.begin(scene.dirLight.getCamera());
scene.setClippingPlane(clippingPlaneDisable, 0);
renderComponents(scene, scene.depthBatch, scene.sceneGraph.getRoot(), null, true);
scene.modelCacheManager.triggerBeforeDepthRenderEvent();
scene.depthBatch.render(scene.modelCacheManager.modelCache, scene.environment);
scene.depthBatch.end();
scene.dirLight.end();
}

public void renderSkybox(Scene scene) {
if (scene.skybox != null && scene.skybox.active) {
scene.batch.render(scene.skybox.getSkyboxInstance(), scene.environment, scene.skybox.shader);
Expand All @@ -163,4 +141,25 @@ public void setDepthShader(Shader depthShader) {
public Shader getDepthShader() {
return depthShader;
}

@Override
public void setShadowMapStrategy(ShadowMapStrategy shadowMapStrategy, Environment environment) {
if (this.shadowMapStrategy != null) {
environment.remove(this.shadowMapStrategy.getAttribute().type);
this.shadowMapStrategy.dispose();
}
this.shadowMapStrategy = shadowMapStrategy;
environment.set(shadowMapStrategy.getAttribute());
}

@Override
public ShadowMapStrategy getShadowMapStrategy() {
return shadowMapStrategy;
}

@Override
public void dispose() {
waterRenderer.dispose();
shadowMapStrategy.dispose();
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.mbrlabs.mundus.commons.rendering;

import com.badlogic.gdx.graphics.g3d.Environment;
import com.badlogic.gdx.graphics.g3d.ModelBatch;
import com.badlogic.gdx.graphics.g3d.Shader;
import com.mbrlabs.mundus.commons.Scene;
import com.mbrlabs.mundus.commons.shadows.strategy.ShadowMapStrategy;
import com.mbrlabs.mundus.commons.scene3d.GameObject;
import com.mbrlabs.mundus.commons.water.WaterResolution;

Expand Down Expand Up @@ -48,5 +50,9 @@ public interface SceneRenderer {

Shader getDepthShader();

void setShadowMapStrategy(ShadowMapStrategy shadowMapStrategy, Environment environment);

ShadowMapStrategy getShadowMapStrategy();

void updateWaterResolution(WaterResolution waterResolution);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.badlogic.gdx.graphics.glutils.FrameBuffer;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.Disposable;
import com.mbrlabs.mundus.commons.Scene;
import com.mbrlabs.mundus.commons.scene3d.GameObject;
import com.mbrlabs.mundus.commons.scene3d.components.Component;
Expand All @@ -20,7 +21,7 @@
* @author JamesTKhan
* @version October 03, 2023
*/
public class WaterRenderer {
public class WaterRenderer implements Disposable {

protected static final Vector3 clippingPlaneReflection = new Vector3(0.0f, 1f, 0.0f);
protected static final Vector3 clippingPlaneRefraction = new Vector3(0.0f, -1f, 0.0f);
Expand Down Expand Up @@ -197,4 +198,17 @@ public void updateWaterResolution(WaterResolution waterResolution) {
Vector2 res = waterResolution.getResolutionValues();
updateFBOS((int) res.x, (int) res.y);
}

@Override
public void dispose() {
if (fboWaterReflection != null) {
fboWaterReflection.dispose();
}
if (fboWaterRefraction != null) {
fboWaterRefraction.dispose();
}
if (fboDepthRefraction != null) {
fboDepthRefraction.dispose();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.g3d.Renderable;
import com.badlogic.gdx.graphics.g3d.Shader;
import com.mbrlabs.mundus.commons.shadows.ShadowStrategyAttribute;
import com.mbrlabs.mundus.commons.terrain.SplatTexture;
import com.mbrlabs.mundus.commons.terrain.TerrainMaterial;
import com.mbrlabs.mundus.commons.terrain.attributes.TerrainMaterialAttribute;
Expand Down Expand Up @@ -31,6 +32,13 @@ protected Shader createShader(Renderable renderable) {

@Override
protected PBRShader createShader(Renderable renderable, PBRShaderConfig config, String prefix){

if (renderable.environment != null) {
if (renderable.environment.get(ShadowStrategyAttribute.VarianceShadowMap) != null) {
prefix += "#define " + ShadowStrategyAttribute.VarianceShadowMapAlias + "Flag\n";
}
}

if (renderable.material.has(TerrainMaterialAttribute.TerrainMaterial)) {
return createPBRTerrainShader(renderable, config, prefix);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.mbrlabs.mundus.commons.shaders;

import com.mbrlabs.mundus.commons.shadows.ShadowStrategyAttribute;
import com.mbrlabs.mundus.commons.utils.ShaderUtils;

/**
* @author JamesTKhan
* @version October 02, 2023
*/
public class VarianceDepthShader extends DepthShader {
protected static final String FRAGMENT_SHADER = "com/mbrlabs/mundus/commons/shaders/depth.vsm.frag.glsl";

public VarianceDepthShader() {
String prefix = "#define " + ShadowStrategyAttribute.VarianceShadowMapAlias + "Flag\n";
program = ShaderUtils.compile(VERTEX_SHADER, FRAGMENT_SHADER, this, prefix);
}

}
Loading