Have built a test case.
Making a simple revolving snowflake that is made from two quads crossed together.
As the snowflake revolves you will notice that on one side of the quad it completely culls the second quad, but on the second side of the quad it blends the transparency.
How do you make both sides of the quad transparent and behave the same.
import javax.imageio.ImageIO;
import com.jme.app.SimpleGame;
import com.jme.bounding.BoundingBox;
import com.jme.image.Texture;
import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.renderer.Renderer;
import com.jme.scene.Node;
import com.jme.scene.shape.Quad;
import com.jme.scene.state.AlphaState;
import com.jme.scene.state.CullState;
import com.jme.scene.state.TextureState;
import com.jme.system.DisplaySystem;
import com.jme.util.TextureManager;
public class TestAlpha extends SimpleGame {
private Quad quad;
private Node snowFlake;
private Quaternion rotQuat = new Quaternion();
private Quaternion rotQuatSnowFlake = new Quaternion();
private float angle = 0;
private float angleSnowFlake = 0;
private Vector3f axis = new Vector3f(0, 1, 0);
private Vector3f axisSnowFlake = new Vector3f(0, 1, 0);
public static void main(String[] args) {
TestAlpha app = new TestAlpha();
app.setDialogBehaviour(ALWAYS_SHOW_PROPS_DIALOG);
app.start();
}
/**
* Rotates the dome
*/
protected void simpleUpdate() {
if (tpf < 1) {
angle = angle + (tpf * 1);
if (angle > 360) {
angle = 0;
}
angleSnowFlake = angleSnowFlake + (tpf*1.1f);
if (angleSnowFlake > 360) {
angle = 0;
}
}
rotQuat.fromAngleAxis(angle, axis);
quad.setLocalRotation(rotQuat);
rotQuatSnowFlake.fromAngleAxis(angleSnowFlake, axisSnowFlake);
snowFlake.setLocalRotation(rotQuatSnowFlake);
}
/*
* (non-Javadoc)
*
* @see com.jme.app.SimpleGame#initGame()
*/
protected void simpleInitGame() {
display.setTitle("jME - Quad");
addRevolvingGlassPane();
quad.updateGeometricState(0,false);
quad.updateRenderState();
rootNode.attachChild(quad);
addRevolvingSnowflake();
snowFlake.updateGeometricState(0,false);
snowFlake.updateRenderState();
rootNode.attachChild(snowFlake);
}
private void addRevolvingGlassPane() {
quad = new Quad("quad", 20, 20);
quad.setLocalTranslation(new Vector3f(0, 0, -40));
quad.setModelBound(new BoundingBox());
quad.updateModelBound();
TextureState ts = getTextureState("/jmetest/data/texture/flare1.png");
quad.setRenderState(ts);
AlphaState as = getAlpha();
quad.setRenderState(as);
quad.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT);
}
private void addRevolvingSnowflake() {
snowFlake = new Node("Snowflake");
Quad q1 = new Quad("q1", 25,25);
q1.setModelBound(new BoundingBox());
q1.updateModelBound();
Quad q2 = new Quad("q2", 25,25);
q2.setModelBound(new BoundingBox());
q2.updateModelBound();
TextureState ts = getTextureState("/jmetest/data/texture/flare1.png");
q1.setRenderState(ts);
q2.setRenderState(ts);
q1.setRenderState( getAlpha());
q1.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT);
q2.setRenderState(getAlpha());
q2.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT);
q1.getLocalTranslation().y = -(25 /2f);
q2.getLocalTranslation().y = -(25 /2f);
CullState cullstate = DisplaySystem.getDisplaySystem().getRenderer().createCullState();
cullstate.setCullMode(CullState.CS_NONE);
q1.setRenderState(cullstate);
q2.setRenderState(cullstate);
Quaternion q = q2.getLocalRotation();
q = q1.getLocalRotation();
q.fromAngles(new float[] { FastMath.DEG_TO_RAD * 90f, FastMath.DEG_TO_RAD * 90f, FastMath.DEG_TO_RAD * 90f});
snowFlake.attachChild(q1);
snowFlake.attachChild(q2);
q = snowFlake.getLocalRotation();
q.fromAngleAxis(FastMath.DEG_TO_RAD * 180, q.getRotationColumn(2));
}
private AlphaState getAlpha() {
AlphaState as = DisplaySystem.getDisplaySystem().getRenderer().createAlphaState();
as.setBlendEnabled(true);
as.setSrcFunction(AlphaState.SB_SRC_ALPHA);
as.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA );
as.setTestEnabled(true);
as.setTestFunction(AlphaState.TF_GREATER);
as.setReference( 0.6f );
as.setEnabled(true);
return as;
}
private TextureState getTextureState(String image) {
TextureState ts = DisplaySystem.getDisplaySystem().getRenderer().createTextureState();
Texture t = TextureManager.loadTexture(getImage(image), Texture.MM_LINEAR_LINEAR, Texture.FM_LINEAR, false);
t.setApply(Texture.AM_ADD);
t.setCombineFuncRGB(Texture.ACF_ADD_SIGNED);
t.setCombineSrc0RGB(Texture.ACS_TEXTURE);
t.setCombineOp0RGB(Texture.ACO_SRC_COLOR);
t.setCombineSrc1RGB(Texture.ACS_PREVIOUS);
t.setCombineOp1RGB(Texture.ACO_SRC_COLOR);
t.setCombineScaleRGB(1.0f);
ts.setTexture(t);
return ts;
}
private BufferedImage getImage(String pathAndName) {
BufferedImage image = null;
try {
image = ImageIO.read(TestAlpha.class.getResource(pathAndName));
} catch(Exception e) {
// cop out just make one
image = new BufferedImage(4,4,1);
}
return image;
}
}