Hello!
My last try posting this was a double post and both posts got removed, so i am trying once again…
I have a problem with transparency and my own custom camera.
As long as i use the FlyByCamera, the following works as expected (the Sphere is visible through the transparent parts of the Box).
[java] Box boxshape3 = new Box(new Vector3f(0f, 0f, 0f), 1f, 1f, 0.01f);
Geometry window_frame = new Geometry("window frame", boxshape3);
Material mat_tt = new Material(assetManager,
"Common/MatDefs/Misc/SimpleTextured.j3md");
mat_tt.setTexture("m_ColorMap", assetManager
.loadTexture("Textures/ColoredTex/Monkey.png"));
mat_tt.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
window_frame.setMaterial(mat_tt);
rootNode.attachChild(window_frame);
Sphere s1 = new Sphere(20, 40, 3f);
Geometry geoms1 = new Geometry("Sphere", s1);
Material mats1 = new Material(assetManager,
"Common/MatDefs/Misc/SimpleTextured.j3md");
mats1.setTexture("m_ColorMap", assetManager
.loadTexture("Textures/ColoredTex/Monkey.png"));
geoms1.setLocalTranslation(new Vector3f(0f, 20f, -30f));
geoms1.setMaterial(mats1);
rootNode.attachChild(geoms1);[/java]
However, when I use my own slightly modified SimpleApplication (SimpleGame2D) along with my own camera (StrategyCamera), the transparency ceases to work. Instead its all black in the transparent parts.
SimpleGame2D:
[java]package de.fha.jme3;
import com.jme3.app.Application;
import com.jme3.app.StatsView;
import com.jme3.font.BitmapFont;
import com.jme3.font.BitmapText;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial.CullHint;
import com.jme3.system.AppSettings;
import com.jme3.system.JmeSystem;
import com.jme3.system.JmeContext.Type;
import com.jme3.util.BufferUtils;
public abstract class SimpleGame2D extends Application {
protected Node rootNode = new Node("Root Node");
protected Node guiNode = new Node("Gui Node");
protected float secondCounter = 0.0f;
protected BitmapText fpsText;
protected BitmapFont guiFont;
protected StatsView statsView;
protected StrategyCamera stratCam;
protected boolean showSettings = true;
private AppActionListener actionListener = new AppActionListener();
private class AppActionListener implements ActionListener {
public void onAction(String name, boolean value, float tpf) {
if (!value)
return;
if (name.equals("SIMPLEAPP_Exit")) {
stop();
} else if (name.equals("SIMPLEAPP_CameraPos")) {
if (cam != null) {
Vector3f loc = cam.getLocation();
Quaternion rot = cam.getRotation();
System.out.println("Camera Position: (" + loc.x + ", "
- loc.y + ", " + loc.z + ")");
System.out.println("Camera Rotation: " + rot);
System.out.println("Camera Direction: "
- cam.getDirection());
}
} else if (name.equals("SIMPLEAPP_Memory")) {
BufferUtils.printCurrentDirectMemory(null);
}
}
}
public SimpleGame2D() {
super();
}
@Override
public void start() {
// set some default settings in-case
// settings dialog is not shown
if (settings == null) {
settings = new AppSettings(false);
settings.put("Width", 1920);
settings.put("Height", 1080);
settings.put("BitsPerPixel", 32);
settings.put("Frequency", 60);
settings.put("DepthBits", 24);
settings.put("StencilBits", 0);
settings.put("Samples", 4);
settings.put("Fullscreen", true);
settings.put("Title", "jMonkey Engine 3.0");
settings.put("Renderer", AppSettings.LWJGL_OPENGL2);
settings.put("AudioRenderer", AppSettings.LWJGL_OPENAL);
settings.put("DisableJoysticks", true);
settings.put("UseInput", true);
settings.put("VSync", true);
settings.put("FrameRate", 60);
}
// show settings dialog
if (showSettings) {
if (!JmeSystem.showSettingsDialog(settings))
return;
}
super.start();
}
public StrategyCamera getStrategyCamera() {
return stratCam;
}
public Node getGuiNode() {
return guiNode;
}
public Node getRootNode() {
return rootNode;
}
public boolean isShowSettings() {
return showSettings;
}
public void setShowSettings(boolean showSettings) {
this.showSettings = showSettings;
}
public void loadFPSText() {
guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
fpsText = new BitmapText(guiFont, false);
fpsText.setSize(guiFont.getCharSet().getRenderedSize());
fpsText.setLocalTranslation(0, fpsText.getLineHeight(), 0);
fpsText.setText("Frames per second");
guiNode.attachChild(fpsText);
}
public void loadStatsView() {
statsView = new StatsView("Statistics View", assetManager, renderer
.getStatistics());
// move it up so it appears above fps text
statsView.setLocalTranslation(0, fpsText.getLineHeight(), 0);
guiNode.attachChild(statsView);
}
@Override
public void initialize() {
super.initialize();
guiNode.setQueueBucket(Bucket.Gui);
guiNode.setCullHint(CullHint.Never);
loadFPSText();
loadStatsView();
viewPort.attachScene(rootNode);
guiViewPort.attachScene(guiNode);
if (inputManager != null) {
stratCam = new StrategyCamera(cam);
stratCam.registerWithInput(inputManager);
if (context.getType() == Type.Display)
inputManager.addMapping("SIMPLEAPP_Exit", new KeyTrigger(
KeyInput.KEY_ESCAPE));
inputManager.addMapping("SIMPLEAPP_CameraPos", new KeyTrigger(
KeyInput.KEY_C));
inputManager.addMapping("SIMPLEAPP_Memory", new KeyTrigger(
KeyInput.KEY_M));
inputManager.addListener(actionListener, "SIMPLEAPP_Exit",
"SIMPLEAPP_CameraPos", "SIMPLEAPP_Memory");
}
// call user code
simpleInitApp();
}
@Override
public void update() {
if (speed == 0 || paused)
return;
super.update();
float tpf = timer.getTimePerFrame() * speed;
secondCounter += timer.getTimePerFrame();
int fps = (int) timer.getFrameRate();
if (secondCounter >= 1.0f) {
fpsText.setText("Frames per second: " + fps);
secondCounter = 0.0f;
}
// update camera
stratCam.update(tpf);
// update states
stateManager.update(tpf);
// simple update and root node
simpleUpdate(tpf);
rootNode.updateLogicalState(tpf);
guiNode.updateLogicalState(tpf);
rootNode.updateGeometricState();
guiNode.updateGeometricState();
// render states
stateManager.render(renderManager);
renderManager.render(tpf);
simpleRender(renderManager);
}
public abstract void simpleInitApp();
public void simpleUpdate(float tpf) {
}
public void simpleRender(RenderManager rm) {
}
}
[/java]
StrategyCamera:
[java]package de.fha.jme3;
import com.jme3.input.FlyByCamera;
import com.jme3.input.InputManager;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.controls.MouseAxisTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.math.FastMath;
import com.jme3.math.Matrix3f;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
public class StrategyCamera implements AnalogListener, ActionListener {
private static final String COMMAND_MOUSE_IN = "STRATCAM_Mouse_In";
private static final String COMMAND_MOUSE_OUT = "STRATCAM_Mouse_Out";
private static final String COMMAND_MOUSE_LEFT = "STRATCAM_Mouse_Left";
private static final String COMMAND_MOUSE_RIGHT = "STRATCAM_Mouse_Right";
private static final String COMMAND_MOUSE_UP = "STRATCAM_Mouse_Up";
private static final String COMMAND_MOUSE_DOWN = "STRATCAM_Mouse_Down";
private static final String COMMAND_MOUSE_MIDDLE_DRAG = "STRATCAM_Mouse_Middle_Drag";
private InputManager inputManager;
private Camera cam;
private boolean enabled = true;
private Vector3f initialUpVector = new Vector3f(0f, 0f, 1f);
private boolean canRotate;
private float rotationSpeed = 3f;
private Vector3f initialLocation = new Vector3f(0f, -20f, 10f);
private Vector3f initialViewpoint = new Vector3f(0f, 0f, 0f);
private float maxY = 240f;
private float minY = -240f;
private float maxX = 240f;
private float minX = -240f;
private float moveSpeed = 1.35f;
private float movingUp = 0f;
private float movingDown = 0f;
private float movingLeft = 0f;
private float movingRight = 0f;
private float actualMovingUp = 0f;
private float actualMovingDown = 0f;
private float actualMovingLeft = 0f;
private float actualMovingRight = 0f;
private float moveAnimationSpeed = 0.35f;
private float zoomSpeed = 0.3f;
private float zoom = 0f;
private float actualZoom = 1f;
private float zoomAnimationSpeed = 0.2f;
private float maxZoomOut = 22f;
private float minZoomOut = 0f;
private boolean zoomEnabled = true;
private boolean rotatingAllowed = true;
private boolean bankingAllowed = false;
private Vector3f leftVector = new Vector3f(-1f, 0f, 0f);
private Vector3f upVector = new Vector3f(0f, 1f, 0f);
private Vector3f camToViewpoint;
private Vector3f camToCursorpoint;
public StrategyCamera(Camera cam) {
this.cam = cam;
this.cam.setFrustumPerspective(45, ((float) cam.getWidth())
/ ((float) this.cam.getHeight()), 0.01f, 10000f);
this.cam.setLocation(initialLocation);
zoom = FastMath.log(cam.getLocation().z) / zoomSpeed;
actualZoom = zoom;
camToViewpoint = initialViewpoint.subtract(cam.getLocation());
this.cam.setDirection(camToViewpoint.normalize());
}
private void updateCamToViewpoint() {
Vector3f camLocation = cam.getLocation();
Vector3f camDirection = cam.getDirection();
camToViewpoint = camDirection.mult(-camLocation.z / camDirection.z);
}
private void updateCamToCursorpoint() {
Vector2f cursor = inputManager.getCursorPosition();
Vector3f direction = cam.getLocation().subtract(
cam.getWorldCoordinates(cursor, 1f));
direction = direction.mult(-cam.getLocation().z / direction.z);
camToCursorpoint = direction;
}
public void update(float tpf) {
actualMovingUp += (movingUp - actualMovingUp) * moveAnimationSpeed;
actualMovingDown += (movingDown - actualMovingDown)
- moveAnimationSpeed;
actualMovingLeft += (movingLeft - actualMovingLeft)
- moveAnimationSpeed;
actualMovingRight += (movingRight - actualMovingRight)
- moveAnimationSpeed;
if (actualMovingUp > 0.01f) {
keyUp(tpf * actualMovingUp);
} else if (actualMovingDown > 0.1f) {
keyDown(tpf * actualMovingDown);
}
if (actualMovingLeft > 0.01f) {
keyLeft(tpf * actualMovingLeft);
} else if (actualMovingRight > 0.01f) {
keyRight(tpf * actualMovingRight);
}
updateCamToCursorpoint();
updateCamToViewpoint();
float z = cam.getLocation().z;
float zoomDifference = zoom - actualZoom;
if (zoomDifference < -0.01f) {
actualZoom += zoomDifference * zoomAnimationSpeed;
float targetZ = FastMath.exp(actualZoom * zoomSpeed);
float factor = 1 - (targetZ / z);
cam.setLocation(cam.getLocation()
.add(camToCursorpoint.mult(factor)));
} else if (zoomDifference > 0.01f) {
actualZoom += zoomDifference * zoomAnimationSpeed;
float targetZ = FastMath.exp(actualZoom * zoomSpeed);
float factor = 1 - (targetZ / z);
cam.setLocation(cam.getLocation().add(camToViewpoint.mult(factor)));
}
}
private void rotateCamera(float value, Vector3f axis) {
updateCamToViewpoint();
float length = camToViewpoint.length();
Matrix3f mat = new Matrix3f();
mat.fromAngleNormalAxis(rotationSpeed * value, axis);
Vector3f up = cam.getUp();
Vector3f left = cam.getLeft();
Vector3f dir = cam.getDirection();
mat.mult(up, up);
mat.mult(left, left);
mat.mult(dir, dir);
Quaternion q = new Quaternion();
q.fromAxes(left, up, dir);
q.normalize();
cam.setAxes(q);
up = cam.getUp();
left = cam.getLeft();
Vector3f viewpoint = cam.getLocation().add(camToViewpoint);
Vector3f expectedCamLocation = viewpoint.add(cam.getDirection()
.normalize().mult(-length));
if (expectedCamLocation.z < 1f) {
expectedCamLocation.z = 1f;
}
cam.setLocation(expectedCamLocation);
cam.lookAt(viewpoint, cam.getUp());
zoom = FastMath.log(cam.getLocation().z) / zoomSpeed;
actualZoom = zoom;
leftVector = cam.getLeft().normalize();
upVector = new Vector3f(cam.getUp().x, cam.getUp().y, 0f).normalize();
if (upVector.equals(new Vector3f(0f, 0f, 0f))) {
upVector = new Vector3f(cam.getDirection().x, cam.getDirection().y,
0f).normalize();
}
}
/**
- Sets the move speed. The speed is given in world units per second.
*
-
@param moveSpeed
*/
public void setMoveSpeed(float moveSpeed) {
this.moveSpeed = moveSpeed;
}
/**
-
@param enable
-
If false, the camera will ignore input.<br />
*/
public void setEnabled(boolean enable) {
enabled = enable;
}
/**
-
@return If enabled
-
@see FlyByCamera#setEnabled(boolean)
*/
public boolean isEnabled() {
return enabled;
}
/**
- Registers the FlyByCamera to receive input events from the provided
- Dispatcher.
*
-
@param dispacher
*/
public void registerWithInput(InputManager inputManager) {
this.inputManager = inputManager;
String[] mappings = new String[] { COMMAND_MOUSE_IN, COMMAND_MOUSE_OUT,
COMMAND_MOUSE_LEFT, COMMAND_MOUSE_RIGHT, COMMAND_MOUSE_UP,
COMMAND_MOUSE_DOWN, COMMAND_MOUSE_MIDDLE_DRAG };
inputManager.addMapping(COMMAND_MOUSE_UP,
new MouseAxisTrigger(1, false));
inputManager.addMapping(COMMAND_MOUSE_DOWN, new MouseAxisTrigger(1,
true));
inputManager.addMapping(COMMAND_MOUSE_RIGHT, new MouseAxisTrigger(0,
false));
inputManager.addMapping(COMMAND_MOUSE_LEFT, new MouseAxisTrigger(0,
true));
inputManager.addMapping(COMMAND_MOUSE_OUT,
new MouseAxisTrigger(2, true));
inputManager.addMapping(COMMAND_MOUSE_IN,
new MouseAxisTrigger(2, false));
inputManager.addMapping(COMMAND_MOUSE_MIDDLE_DRAG,
new MouseButtonTrigger(MouseInput.BUTTON_MIDDLE));
inputManager.addListener(this, mappings);
}
public void onAction(String name, boolean value, float tpf) {
if (name.equals(COMMAND_MOUSE_MIDDLE_DRAG)) {
canRotate = value;
}
}
private void mouseWheel(float value) {
if (zoomEnabled) {
updateCamToCursorpoint();
Vector3f cursorpoint = cam.getLocation().add(camToCursorpoint);
if (isInBounds(cursorpoint) || value > 0f) {
zoom += value;
if (zoom > maxZoomOut) {
zoom = maxZoomOut;
} else if (zoom < minZoomOut) {
zoom = minZoomOut;
}
}
}
}
private boolean isInBounds(Vector3f vector) {
return !(vector.x > maxX || vector.x < minX || vector.y > maxY || vector.y < minY);
}
private void moveCamera(float value, Vector3f direction) {
updateCamToViewpoint();
Vector3f movement = direction.normalize().mult(
value * moveSpeed * camToViewpoint.length());
Vector3f viewpoint = cam.getLocation().add(camToViewpoint);
Vector3f newViewpoint = viewpoint.add(movement);
if (!isInBounds(newViewpoint)) {
if (newViewpoint.x > maxX) {
newViewpoint.x = maxX;
} else if (newViewpoint.x < minX) {
newViewpoint.x = minX;
}
if (newViewpoint.y > maxY) {
newViewpoint.y = maxY;
} else if (newViewpoint.y < minY) {
newViewpoint.y = minY;
}
System.out.println(newViewpoint);
movement = newViewpoint.subtract(viewpoint);
}
cam.setLocation(cam.getLocation().add(movement));
}
private void keyUp(float value) {
moveCamera(value, upVector);
}
private void keyDown(float value) {
moveCamera(value, upVector.negate());
}
private void keyLeft(float value) {
moveCamera(value, leftVector);
}
private void keyRight(float value) {
moveCamera(value, leftVector.negate());
}
private void mouseLeft() {
float x = inputManager.getCursorPosition().x;
if (x <= cam.getWidth() - 2) {
movingRight = 0f;
if (x < 2) {
movingLeft = 1f;
}
}
}
private void mouseRight() {
float x = inputManager.getCursorPosition().x;
if (x >= 2) {
movingLeft = 0f;
if (x > cam.getWidth() - 2) {
movingRight = 1f;
}
}
}
private void mouseUp() {
float y = inputManager.getCursorPosition().y;
if (y >= 2) {
movingDown = 0f;
if (y > cam.getHeight() - 2) {
movingUp = 1f;
}
}
}
private void mouseDown() {
float y = inputManager.getCursorPosition().y;
if (y <= cam.getHeight() - 2) {
movingUp = 0f;
if (y < 2) {
movingDown = 1f;
}
}
}
public void onAnalog(String name, float value, float tpf) {
if (!enabled) {
return;
}
if (name.equals(COMMAND_MOUSE_IN)) {
mouseWheel(-value);
} else if (name.equals(COMMAND_MOUSE_OUT)) {
mouseWheel(value);
} else if (name.equals(COMMAND_MOUSE_LEFT)) {
if (!canRotate) {
mouseLeft();
} else if (rotatingAllowed) {
rotateCamera(value, initialUpVector);
}
} else if (name.equals(COMMAND_MOUSE_RIGHT)) {
if (!canRotate) {
mouseRight();
} else if (rotatingAllowed) {
rotateCamera(-value, initialUpVector);
}
} else if (name.equals(COMMAND_MOUSE_UP)) {
if (!canRotate) {
mouseUp();
} else if (bankingAllowed) {
rotateCamera(-value, cam.getLeft());
}
} else if (name.equals(COMMAND_MOUSE_DOWN)) {
if (!canRotate) {
mouseDown();
} else if (bankingAllowed) {
rotateCamera(value, cam.getLeft());
}
}
}
}
[/java]
The only substantial difference between this and the original combination of SimpleApplication and FlyByCamera that i could find is that my StrategyCamera (which I’d happily share with you once i get it to work properly) has its own update()-method that is called by the update()-method of SimpleGame2D.
I tried to put the update()-call in different lines in SimpleGame2D.update() but to no effect. I guess i must have omitted some crucial updating stuff, but I have no idea what it is. I hope you can help me.
By the way: I need this update() on the StrategyCamera in order to smooth zooming and moving around. If there is a better way to do that, i am all ears (or rather eyes).