I am currently trying to set up a panorama viewer in JavaFX using its 3D features. I think I got the geometry right (3D sub-scene, TriangleMesh, etc.) but I am fighting with the proper lighting. What I need is actually no lighting at all, just the geometrically correct display of the original colors of the texture image. JavaFX seems to introduce some unwanted default lighting if there is no explicit lighting specified and is driving me crazy.
Can anybody tell me how to set up the material and the light sources and maybe other related stuff if I do not want to have any lighting at all but just the plain image (texture) colors?
Edit: Here is the requested code example. When the box is rotating you clearly see the corners of the box due to the lighting. If you could switch off the lighting these corners should disappear.
import javafx.animation.Interpolator;
import javafx.animation.RotateTransition;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.SubScene;
import javafx.scene.image.Image;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.CullFace;
import javafx.scene.shape.DrawMode;
import javafx.scene.shape.MeshView;
import javafx.scene.shape.TriangleMesh;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
import javafx.util.Duration;
public class SimplePanoViewer extends Application {
private static final int VIEWPORT_SIZE = 1200;
private static final double MODEL_SCALE_FACTOR = VIEWPORT_SIZE/2;
private static final String textureLoc = "http://www.f-lohmueller.de/pov_tut/backgrnd/im/Cubemap_2_2048x1536.jpg";
private Image texture;
private PhongMaterial texturedMaterial = new PhongMaterial();
private MeshView meshView = loadMeshView();
private MeshView loadMeshView() {
float[] points = {
-0.5f, -0.5f, -0.5f,
-0.5f, +0.5f, -0.5f,
+0.5f, +0.5f, -0.5f,
+0.5f, -0.5f, -0.5f,
-0.5f, -0.5f, +0.5f,
-0.5f, +0.5f, +0.5f,
+0.5f, +0.5f, +0.5f,
+0.5f, -0.5f, +0.5f
};
float TX0 = 0f;
float TX1 = 1f/4f;
float TX2 = 2f/4f;
float TX3 = 3f/4f;
float TX4 = 1f;
float TY0 = 0f;
float TY1 = 1f/3f;
float TY2 = 2f/3f;
float TY3 = 1f;
float[] texCoords = {
TX0, TY1,
TX0, TY2,
TX1, TY2,
TX1, TY3,
TX2, TY3,
TX2, TY2,
TX3, TY2,
TX4, TY2,
TX4, TY1,
TX3, TY1,
TX2, TY1,
TX2, TY0,
TX1, TY0,
TX1, TY1,
};
int[] faces = {
0, 0, 1, 1, 5, 2, 5, 2, 4, 13, 0, 0, // 0
4, 13, 5, 2, 6, 5, 6, 5, 7, 10, 4, 13, // 1
7, 10, 6, 5, 2, 6, 2, 6, 3, 9, 7, 10, // 2
3, 9, 2, 6, 1, 7, 1, 7, 0, 8, 3, 9, // 3
0, 12, 4, 13, 7, 10, 7, 10, 3, 11, 0, 12, // 4
5, 2, 1, 3, 2, 4, 2, 4, 6, 5, 5, 2 // 5
};
TriangleMesh mesh = new TriangleMesh();
mesh.getPoints().setAll(points);
mesh.getTexCoords().setAll(texCoords);
mesh.getFaces().setAll(faces);
return new MeshView(mesh);
}
private Group buildScene() {
meshView.setTranslateX(VIEWPORT_SIZE / 2);
meshView.setTranslateY(VIEWPORT_SIZE / 2 * 9.0 / 16);
meshView.setTranslateZ(-VIEWPORT_SIZE );
meshView.setScaleX(MODEL_SCALE_FACTOR);
meshView.setScaleY(MODEL_SCALE_FACTOR);
meshView.setScaleZ(MODEL_SCALE_FACTOR);
return new Group(meshView);
}
@Override
public void start(Stage stage) {
texture = new Image(textureLoc);
texturedMaterial.setDiffuseMap(texture);
Group group = buildScene();
RotateTransition rotate = rotate3dGroup(group);
meshView.setCullFace(CullFace.NONE);
meshView.setDrawMode(DrawMode.FILL);
rotate.play();
meshView.setMaterial(texturedMaterial);
VBox layout = new VBox(
createScene3D(group)
);
stage.setTitle("Model Viewer");
Scene scene = new Scene(layout, Color.CORNSILK);
stage.setScene(scene);
stage.show();
}
private SubScene createScene3D(Group group) {
SubScene scene3d = new SubScene(group, VIEWPORT_SIZE, VIEWPORT_SIZE * 9.0/16);
scene3d.setFill(Color.rgb(10, 10, 40));
PerspectiveCamera camera = new PerspectiveCamera();
scene3d.setCamera(camera);
return scene3d;
}
private RotateTransition rotate3dGroup(Group group) {
RotateTransition rotate = new RotateTransition(Duration.seconds(30), group);
rotate.setAxis(Rotate.Y_AXIS);
rotate.setFromAngle(0);
rotate.setToAngle(360);
rotate.setInterpolator(Interpolator.LINEAR);
rotate.setCycleCount(RotateTransition.INDEFINITE);
return rotate;
}
public static void main(String[] args) {
launch(args);
}
}
I'am not a solid profi on JavaFX 3D, but I'll try to answer. JavaFX 3D needs light to be able to show a perspective view. If you switch light off, your Subscene renders to black.
There are only two Lights in JavaFX, an AmbientLight and a PointLight. Both can be added to the group where the meshview is added. JavaDoc says about AmbientLight:
Whereas PointLight got this description:
If no Light was added to a Scene or SubScene, it adds a default PointLight that shines from top onto the 3D-Shape. If you add a Light (Ambient or Point) than the default one is removed.
If you would like to place a light, than you should do it in your build scene method.
The lights shown below, are the Default light, PointerLight and AmbientLight. As you can see, the perspective is fully gone if you set ambient light.
Code for testing: