add custom CameraGroupStrategy implementation just to have it's shader do a simple alpha-test on fragments
This commit is contained in:
parent
a3f0cf068f
commit
c1fd43cd64
220
src/com/blarg/gdx/graphics/AlphaTestCameraGroupStrategy.java
Normal file
220
src/com/blarg/gdx/graphics/AlphaTestCameraGroupStrategy.java
Normal file
|
@ -0,0 +1,220 @@
|
||||||
|
package com.blarg.gdx.graphics;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.Gdx;
|
||||||
|
import com.badlogic.gdx.graphics.Camera;
|
||||||
|
import com.badlogic.gdx.graphics.GL10;
|
||||||
|
import com.badlogic.gdx.graphics.g3d.decals.Decal;
|
||||||
|
import com.badlogic.gdx.graphics.g3d.decals.DecalMaterial;
|
||||||
|
import com.badlogic.gdx.graphics.g3d.decals.GroupStrategy;
|
||||||
|
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
|
||||||
|
import com.badlogic.gdx.utils.Array;
|
||||||
|
import com.badlogic.gdx.utils.Disposable;
|
||||||
|
import com.badlogic.gdx.utils.ObjectMap;
|
||||||
|
import com.badlogic.gdx.utils.Pool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* <strong>Note:</strong><br />
|
||||||
|
* This is almost exactly the same as {@link com.badlogic.gdx.graphics.g3d.decals.CameraGroupStrategy} except that
|
||||||
|
* this version requires shader support and it's shader has been slightly modified to perform a simple alpha-test
|
||||||
|
* in the fragment shader.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Minimalistic grouping strategy that splits decals into opaque and transparent ones enabling and disabling blending as needed.
|
||||||
|
* Opaque decals are rendered first (decal color is ignored in opacity check).<br/>
|
||||||
|
* Use this strategy only if the vast majority of your decals are opaque and the few transparent ones are unlikely to overlap.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* Can produce invisible artifacts when transparent decals overlap each other.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* Needs to be explicitely disposed as it might allocate a ShaderProgram when GLSL 2.0 is used.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* States (* = any, EV = entry value - same as value before flush):<br/>
|
||||||
|
* <table>
|
||||||
|
* <tr>
|
||||||
|
* <td></td>
|
||||||
|
* <td>expects</td>
|
||||||
|
* <td>exits on</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>glDepthMask</td>
|
||||||
|
* <td>true</td>
|
||||||
|
* <td>EV</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>GL_DEPTH_TEST</td>
|
||||||
|
* <td>enabled</td>
|
||||||
|
* <td>EV</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>glDepthFunc</td>
|
||||||
|
* <td>GL_LESS | GL_LEQUAL</td>
|
||||||
|
* <td>EV</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>GL_BLEND</td>
|
||||||
|
* <td>disabled</td>
|
||||||
|
* <td>EV | disabled</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>glBlendFunc</td>
|
||||||
|
* <td>*</td>
|
||||||
|
* <td>*</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>GL_TEXTURE_2D</td>
|
||||||
|
* <td>*</td>
|
||||||
|
* <td>disabled</td>
|
||||||
|
* </tr>
|
||||||
|
* </table>
|
||||||
|
* </p> */
|
||||||
|
public class AlphaTestCameraGroupStrategy implements GroupStrategy, Disposable {
|
||||||
|
private static final int GROUP_OPAQUE = 0;
|
||||||
|
private static final int GROUP_BLEND = 1;
|
||||||
|
|
||||||
|
Pool<Array<Decal>> arrayPool = new Pool<Array<Decal>>(16) {
|
||||||
|
@Override
|
||||||
|
protected Array<Decal> newObject () {
|
||||||
|
return new Array<Decal>();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Array<Array<Decal>> usedArrays = new Array<Array<Decal>>();
|
||||||
|
ObjectMap<DecalMaterial, Array<Decal>> materialGroups = new ObjectMap<DecalMaterial, Array<Decal>>();
|
||||||
|
|
||||||
|
Camera camera;
|
||||||
|
ShaderProgram shader;
|
||||||
|
private final Comparator<Decal> cameraSorter;
|
||||||
|
|
||||||
|
public AlphaTestCameraGroupStrategy (final Camera camera) {
|
||||||
|
this(camera, new Comparator<Decal>() {
|
||||||
|
@Override
|
||||||
|
public int compare (Decal o1, Decal o2) {
|
||||||
|
float dist1 = camera.position.dst(o1.getPosition());
|
||||||
|
float dist2 = camera.position.dst(o2.getPosition());
|
||||||
|
return (int)Math.signum(dist2 - dist1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public AlphaTestCameraGroupStrategy(Camera camera, Comparator<Decal> sorter) {
|
||||||
|
if (!Gdx.graphics.isGL20Available())
|
||||||
|
throw new UnsupportedOperationException("AlphaTestCameraGroupStrategy requires shader support.");
|
||||||
|
|
||||||
|
this.camera = camera;
|
||||||
|
this.cameraSorter = sorter;
|
||||||
|
createDefaultShader();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCamera (Camera camera) {
|
||||||
|
this.camera = camera;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Camera getCamera () {
|
||||||
|
return camera;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int decideGroup (Decal decal) {
|
||||||
|
return decal.getMaterial().isOpaque() ? GROUP_OPAQUE : GROUP_BLEND;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeGroup (int group, Array<Decal> contents) {
|
||||||
|
if (group == GROUP_BLEND) {
|
||||||
|
Gdx.gl.glEnable(GL10.GL_BLEND);
|
||||||
|
contents.sort(cameraSorter);
|
||||||
|
} else {
|
||||||
|
for (int i = 0, n = contents.size; i < n; i++) {
|
||||||
|
Decal decal = contents.get(i);
|
||||||
|
Array<Decal> materialGroup = materialGroups.get(decal.getMaterial());
|
||||||
|
if (materialGroup == null) {
|
||||||
|
materialGroup = arrayPool.obtain();
|
||||||
|
materialGroup.clear();
|
||||||
|
usedArrays.add(materialGroup);
|
||||||
|
materialGroups.put(decal.getMaterial(), materialGroup);
|
||||||
|
}
|
||||||
|
materialGroup.add(decal);
|
||||||
|
}
|
||||||
|
|
||||||
|
contents.clear();
|
||||||
|
for (Array<Decal> materialGroup : materialGroups.values()) {
|
||||||
|
contents.addAll(materialGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
materialGroups.clear();
|
||||||
|
arrayPool.freeAll(usedArrays);
|
||||||
|
usedArrays.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterGroup (int group) {
|
||||||
|
if (group == GROUP_BLEND) {
|
||||||
|
Gdx.gl.glDisable(GL10.GL_BLEND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeGroups () {
|
||||||
|
Gdx.gl.glEnable(GL10.GL_DEPTH_TEST);
|
||||||
|
shader.begin();
|
||||||
|
shader.setUniformMatrix("u_projectionViewMatrix", camera.combined);
|
||||||
|
shader.setUniformi("u_texture", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterGroups () {
|
||||||
|
shader.end();
|
||||||
|
Gdx.gl.glDisable(GL10.GL_TEXTURE_2D);
|
||||||
|
Gdx.gl.glDisable(GL10.GL_DEPTH_TEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createDefaultShader () {
|
||||||
|
String vertexShader = "attribute vec4 " + ShaderProgram.POSITION_ATTRIBUTE + ";\n" //
|
||||||
|
+ "attribute vec4 " + ShaderProgram.COLOR_ATTRIBUTE + ";\n" //
|
||||||
|
+ "attribute vec2 " + ShaderProgram.TEXCOORD_ATTRIBUTE + "0;\n" //
|
||||||
|
+ "uniform mat4 u_projectionViewMatrix;\n" //
|
||||||
|
+ "varying vec4 v_color;\n" //
|
||||||
|
+ "varying vec2 v_texCoords;\n" //
|
||||||
|
+ "\n" //
|
||||||
|
+ "void main()\n" //
|
||||||
|
+ "{\n" //
|
||||||
|
+ " v_color = " + ShaderProgram.COLOR_ATTRIBUTE + ";\n" //
|
||||||
|
+ " v_texCoords = " + ShaderProgram.TEXCOORD_ATTRIBUTE + "0;\n" //
|
||||||
|
+ " gl_Position = u_projectionViewMatrix * " + ShaderProgram.POSITION_ATTRIBUTE + ";\n" //
|
||||||
|
+ "}\n";
|
||||||
|
String fragmentShader = "#ifdef GL_ES\n" //
|
||||||
|
+ "precision mediump float;\n" //
|
||||||
|
+ "#endif\n" //
|
||||||
|
+ "varying vec4 v_color;\n" //
|
||||||
|
+ "varying vec2 v_texCoords;\n" //
|
||||||
|
+ "uniform sampler2D u_texture;\n" //
|
||||||
|
+ "void main()\n"//
|
||||||
|
+ "{\n" //
|
||||||
|
+ " vec4 texColor = texture2D(u_texture, v_texCoords);\n" //
|
||||||
|
+ " if (texColor.a > 0.0)\n" //
|
||||||
|
+ " gl_FragColor = v_color * texture2D(u_texture, v_texCoords);\n" //
|
||||||
|
+ " else\n" //
|
||||||
|
+ " discard;\n" //
|
||||||
|
+ "}";
|
||||||
|
|
||||||
|
shader = new ShaderProgram(vertexShader, fragmentShader);
|
||||||
|
if (shader.isCompiled() == false) throw new IllegalArgumentException("couldn't compile shader: " + shader.getLog());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ShaderProgram getGroupShader (int group) {
|
||||||
|
return shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispose () {
|
||||||
|
if (shader != null) shader.dispose();
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,7 +22,7 @@ public class RenderContext implements Disposable {
|
||||||
public final ScreenPixelScaler pixelScaler;
|
public final ScreenPixelScaler pixelScaler;
|
||||||
public final SolidColorTextureCache solidColorTextures;
|
public final SolidColorTextureCache solidColorTextures;
|
||||||
|
|
||||||
CameraGroupStrategy cameraGroupStrategy;
|
AlphaTestCameraGroupStrategy cameraGroupStrategy;
|
||||||
Camera perspectiveCamera;
|
Camera perspectiveCamera;
|
||||||
OrthographicCamera orthographicCamera;
|
OrthographicCamera orthographicCamera;
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ public class RenderContext implements Disposable {
|
||||||
|
|
||||||
setDefaultPerspectiveCamera();
|
setDefaultPerspectiveCamera();
|
||||||
|
|
||||||
cameraGroupStrategy = new CameraGroupStrategy(perspectiveCamera);
|
cameraGroupStrategy = new AlphaTestCameraGroupStrategy(perspectiveCamera);
|
||||||
decalBatch = new DecalBatch(cameraGroupStrategy);
|
decalBatch = new DecalBatch(cameraGroupStrategy);
|
||||||
billboardSpriteBatch = new BillboardSpriteBatch();
|
billboardSpriteBatch = new BillboardSpriteBatch();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue