Is it possible to create a photosphere in JavaFX that is similar to photoshpere in Google map? If yes, how?
The answer is yes, you can create a photosphere in JavaFX.
As for the how, there's an easy solution based on a sphere from the 3D API, but we can implement an improved solution, with a custom mesh.
Let's start by using a regular sphere. We just need a 360º image, like this one.
As we want to see from the inside of the sphere, we have to flip the image horizontally, and add it to the sphere material's diffusion map.
Then we just need to set up a camera in the very center of the sphere, add some lights and start spinning.
#Override
public void start(Stage primaryStage) {
PerspectiveCamera camera = new PerspectiveCamera(true);
camera.setNearClip(0.1);
camera.setFarClip(10000.0);
camera.setFieldOfView(90);
Sphere sphere = new Sphere(1000);
sphere.setCullFace(CullFace.NONE);
PhongMaterial material = new PhongMaterial();
/*
"SonyCenter 360panorama" by François Reincke - Own work. Made using autostitch (www.autostitch.net)..
Licensed under CC BY-SA 3.0 via Wikimedia Commons - http://commons.wikimedia.org/wiki/File:SonyCenter_360panorama.jpg#mediaviewer/File:SonyCenter_360panorama.jpg
*/
material.setDiffuseMap(new Image(getClass().getResource("SonyCenter_360panorama_reversed.jpg").toExternalForm()));
sphere.setMaterial(material);
Group root3D = new Group(camera,sphere,new AmbientLight(Color.WHITE));
Scene scene = new Scene(root3D, 800, 600, true, SceneAntialiasing.BALANCED);
scene.setCamera(camera);
primaryStage.setTitle("PhotoSphere in JavaFX3D");
primaryStage.setScene(scene);
primaryStage.show();
final Timeline rotateTimeline = new Timeline();
rotateTimeline.setCycleCount(Timeline.INDEFINITE);
camera.setRotationAxis(Rotate.Y_AXIS);
final KeyValue kv1 = new KeyValue(camera.rotateProperty(), 360);
final KeyFrame kf1 = new KeyFrame(Duration.millis(30000), kv1);
rotateTimeline.getKeyFrames().addAll(kf1);
rotateTimeline.play();
}
Now you will want to add some controls to the camera (so you can navigate). You will discover that this solution has a weak spot at the top and bottom of the sphere, due to the fact that all the top or bottom side of the image is located in one point:
You can find a solution to this problem at the F(X)yz library here. A custom mesh called SegmentedSphereMesh allows you to crop the extremes of the sphere, so the image can keep its aspect ratio without being stretched.
If you clone and build the repo, add FXyz.jar to your project, and just replace Sphere in the previous snippet with this:
SegmentedSphereMesh sphere = new SegmentedSphereMesh(100,0,26,1000);
sphere.setCullFace(CullFace.NONE);
sphere.setTextureModeImage(getClass().getResource("SonyCenter_360panorama_reversed.jpg").toExternalForm());
In the same library you can find SkyBox, based on a cube and one square image on each of its faces. Also check the advanced camera options.
Finally, note that this and more 3D advanced shapes are now demonstrated in the F(X)yz-Sampler application.
Related
I am trying to add scaling animation to Transformable Node (3D model) when I tap on it.
Can anyone help me with it?
You can add a scaling animation to Transformable Node using the following code:
Anchor yourAnchor = hitResult.createAnchor();
AnchorNode anchoringNode = new AnchorNode(yourAnchor);
modelNode.getScaleController().setMinScale(1.50f);
modelNode.getScaleController().setMaxScale(2.00f);
modelNode.setLocalScale(new Vector3(1.75f, 1.75f, 1.75f));
modelNode.setParent(anchoringNode);
i want to render model via JPCT-AE and use the ARToolkit to realizing AR Application.
so , i inject the code as below into the ARToolkit Project:
Matrix projMatrix = new Matrix();
projMatrix.setDump(ARNativeActivity.getProjectM());
projMatrix.transformToGL();
SimpleVector translation = projMatrix.getTranslation();
SimpleVector dir = projMatrix.getZAxis();
SimpleVector up = projMatrix.getYAxis();
cameraController.setPosition(translation);
cameraController.setOrientation(dir, up);
Matrix transformM = new Matrix();
transformM .setDump(ARNativeActivity.getTransformationM());
transformM .transformToGL();
model.clearTranslation();
model.translate(transformM .getTranslation());
dump.setRow(3,0.0f,0.0f,0.0f,1.0f);
model.clearRotation();
model.setRotationMatrix(transformM );
And then , the model can be render on the screen but always lie on the mark in the screen, ever i using model.rotateX/Y/Z( (float)Math.PI/2 );
Actually, the matrix output from the ARToolkit::ARNativeActivity.getTransformationMatrix() is correct, and then i split this 4*4Matrix into translation Matrix and Rotation Matrix and set into the model like this:
model.translate(transformM .getTranslation());
model.setRotationMatrix(transformM );
But still no work.
I would suggest to organize better your code, and work with matrices to separate the transformations to make to your model and the transformations to place the model in the marker.
What I suggest is:
First, use an additional matrix. It may be called modelMatrix, as it will store the transformation done to the model (scale, rotation and translation).
Then, declare all matrices outside this method (it is for performance reasons only, but is recommended), and on each frame simply setIdentity to them:
projMatrix.setIdentity();
transformM.setIdentity();
modelM.setIdentity();
later, make the model transformations on the modelM matrix. This transformations will apply to the model, after placed on the marker.
modelM.rotateZ((float) Math.toRadians(-angle+180));
modelM.translate(movementX, movementY, 0);
then, multiply the modelM matrix by the trasnformM (this means you get all the transformations done, and move and rotate them as the transformM describes, which in our case means that all the transformations done to the model are moved on top of the marker).
//now multiply trasnformationMat * modelMat
modelM.matMul(trasnformM);
And finally, apply the rotation and translation to your model:
model.setRotationMatrix(modelM);
model.setTranslationMatrix(modelM);
so the whole code would look as:
projMatrix.setIdentity();
projMatrix.setDump(ARNativeActivity.getProjectM());
projMatrix.transformToGL();
SimpleVector translation = projMatrix.getTranslation();
SimpleVector dir = projMatrix.getZAxis();
SimpleVector up = projMatrix.getYAxis();
cameraController.setPosition(translation);
cameraController.setOrientation(dir, up);
model.clearTranslation();
model.clearRotation();
transformM.setIdentity();
transformM .setDump(ARNativeActivity.getTransformationM());
transformM .transformToGL();
modelM.setIdentity()
//do whatever you want to your model
modelM.rotateZ((float)Math.toRadians(180));
modelM.matMul(transformM);
model.setRotationMatrix(modelM );
model.setTranslationMatrix(modelM);
I strongly reccomend to look at this tutorial about matrices and OpenGL, it is not about JPCT, but all concepts may apply also to there, and it is what I've used to place correctly models in markers with the ARSimple example as you may see in this blog entry I made.
Hope this helps!
I'm creating a game that will mainly run on browser thanks to GWT HTML5 deployment. I have quite a few MB of assets between images and sounds. Obviously I don't need them all at all times. I'd like to load them depending on the screen that's coming next and other parameters. That is specially critical because my main deployment will be on web (can't load all 50MB when starting just in case they will be used).
I don't really know how asset loading works on LibGDX on HTML5 really. I'd like to use the AssetManager or something similar to load my TextureAtlases and Sounds but I think HTML5 deployment just loads everything in the beginning regardless if I later use the AssetManager in the core project.
What would be a correct asset loading pipeline with libGDX and GWT. It would be awesome to load all from the core project because that way would be multiplatform for the future but it is not critical now so the important part is to load assets wisely on the web.
Thanks in advance.
My recommended way of managing assets:
// load texture atlas
final String spriteSheet = "images/spritesheet.pack";
assetManager.load(spriteSheet, TextureAtlas.class);
// blocks until all assets are loaded
assetManager.finishedLoading();
// all assets are loaded, we can now create our TextureAtlas object
TextureAtlas atlas = assetManager.get(spriteSheet);
// (optional) enable texture filtering for pixel smoothing
for (Texture t: atlas.getTextures())
t.setFilter(TextureFilter.Linear, TextureFilter.Linear);
Now to load a sprite you do:
// Create AtlasRegion instance according the given <atlasRegionName>
final String atlasRegionName = "regionName";
AtlasRegion atlasRegion = atlas.findRegion(atlasRegionName);
// adjust your sprite position and dimensions here
final float xPos = 0;
final float yPos = 0;
final float w = asset.getWidth();
final float h = asset.getHeight();
// create sprite from given <atlasRegion>, with given dimensions <w> and <h>
// on the position of the given coordinates <xPos> and <yPos>
Sprite spr = new Sprite(atlasRegion, w, h, xPos, yPos);
I would like to set a background image the same size as my window/screen.
I would prefer to do this in my CSS file, but I have NOT FOUND a way to accomplish this.
Must I do this in a javafx class file?
Thanks for every help ;)
You will have to determine the screen size in java code as demonstrated in JavaFX window sizing, there is no way to determine it in CSS.
For an Image, in your java code you can use something as
ImageView imageView = new ImageView(image);
imageView.setFitWidth(Screen.getPrimary().getVisualBounds().getWidth());
imageView.setFitHeight(Screen.getPrimary().getVisualBounds().getHeight());
If you want to set the background image to a scene then:
import javafx.application.Application;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.*;
public class ScreenSizeImage extends Application {
#Override public void start(final Stage stage) {
// uncomment if you want the stage full screen.
//stage.setFullScreen(true);
Screen screen = Screen.getPrimary();
Rectangle2D bounds = screen.getVisualBounds();
stage.setX(bounds.getMinX());
stage.setY(bounds.getMinY());
stage.setWidth(bounds.getWidth());
stage.setHeight(bounds.getHeight());
StackPane root = new StackPane();
root.setStyle(
"-fx-background-image: url(" +
"'http://icons.iconarchive.com/icons/iconka/meow/256/cat-box-icon.png'" +
"); " +
"-fx-background-size: cover;"
);
stage.setScene(new Scene(root));
stage.show();
}
public static void main(String[] args) { launch(args); }
}
Of course, rather than the inline setStyle call you are best off using a separate CSS stylesheet like below:
.root{
-fx-background-image: url("background_image.jpg");
-fx-background-size: cover;
}
Good question...
Firstly, I think you mean "the size of your app window" in your question. Obviously, you can't have a background image that is larger than your screen if you app window is smaller.
Secondly, here's a snippet from the JavaFX CSS Reference Guide:
http://download.java.net/jdk9/jfxdocs/javafx/scene/doc-files/cssref.html
"...the background and border mechanisms are patterned after the CSS 3 draft backgrounds and borders module. See [4] for a detailed description."
...
[4] CSS Backgrounds and Borders Module Level 3: http://www.w3.org/TR/css3-background/
You can use the JavaFX vendor specific CSS property -fx-background-size with the stretch value as long as your aspect ratio is correct/your dimensions are proportional.
You might also get it to work by trying a combination of auto for one dimension and 100% for another... and some combination of contain... depending on if you can live with a cropped image.
-fx-background-size<bg-size> [ , <bg-size> ]*
<bg-size> = [ <size> | auto ]{1,2} | cover | contain | stretch
A series of values separated by commas. Each bg-size item in the series applies to the corresponding image in the background-image series.
You can get more detail at http://www.w3.org/TR/css3-background/#the-background-image
I'm getting mixed results trying to render a basic alien that was done in Blender:
I export in to Ogre 3D and load it in Eclipse:
Then when I load it in my code and try to render it the material won't render:
Could you tell me what I must do to achieve the full alien in my scene? The code I use in Jmonkeyengine is
Spatial model3 = assetManager
.loadModel("objects/creatures/alien/alien.mesh.xml");
model3.scale(0.3f, 0.3f, 0.3f);
model3.setLocalTranslation(-40.0f, 3.5f, -20.0f);
rootNode.attachChild(model3);
Update
I've got material files like these from the export:
dev#dev-OptiPlex-745:~$ ls workspace/DungeonWorld2/assets/objects/creatures/alien/
alien.mesh Material.002.material Material.005.material
alien.mesh.xml Material.003.material
alien.skeleton.xml Material.004.material
dev#dev-OptiPlex-745:~$
This material code actually produces a material in the scene but it's not the one from blender:
model3.setMaterial( new Material(assetManager,
"Common/MatDefs/Misc/Unshaded.j3md") );
Result:
However, loading a 3D model of an alephant without defining the material does work:
Spatial elephant = (Spatial) assetManager.loadModel("Models/Elephant/Elephant.mesh.xml");
float scale = 0.05f;
elephant.scale(scale,scale,scale);
elephant.setLocalTranslation(-50.0f, 3.5f, -20.0f);
control = elephant.getControl(AnimControl.class);
control.addListener(this);
channel = control.createChannel();
for (String anim : control.getAnimationNames())
System.out.println("elephant can:"+anim);
The above code correctly renders the elephant so why can't I export a mesh like that for the alien? I tried to explcitly load the material but it's not working for me:
Spatial model3 = assetManager
.loadModel("objects/creatures/alien/alien.mesh.xml");
model3.scale(0.3f, 0.3f, 0.3f);
model3.setLocalTranslation(-40.0f, 3.5f, -20.0f);
model3.setMaterial( new Material(assetManager,
"objects/creatures/alien/alien.material") );
rootNode.attachChild(model3);
The above generates an exception and I don't really know what material file it is that I'm loading and what do to with the two or three other material files that the export generated:
java.lang.ClassCastException: com.jme3.material.MaterialList cannot be cast to com.jme3.material.MaterialDef
at com.jme3.material.Material.<init>(Material.java:116)
at adventure.Main.simpleInitApp(Main.java:309)
at com.jme3.app.SimpleApplication.initialize(SimpleApplication.java:225)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.initInThread(LwjglAbstractDisplay.java:129)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:205)
at java.lang.Thread.run(Thread.java:679)
Update
Loading other models this way is working:
BlenderKey blenderKey = new BlenderKey(
"objects/creatures/troll/troll.mesh.xml");
Spatial troll = (Spatial) assetManager.loadModel(blenderKey);
troll.setLocalTranslation(new Vector3f(-145, 15, -10));
rootNode.attachChild(troll);
BlenderKey blenderKey2 = new BlenderKey(
"objects/creatures/spaceman/man.mesh.xml");
Spatial man = (Spatial) assetManager.loadModel(blenderKey2);
man.setLocalTranslation(new Vector3f(-140, 15, -10));
rootNode.attachChild(man);
I get the models inside my game and they look alreight, both the troll and the spaceman that both originally were .blend files.
Now it's much better when I did it over and it is loading the material. The only problem with the alien left now is the holes in the head that was also answered here.
BlenderKey blenderKey = new BlenderKey(
"objects/creatures/alien/alien.mesh.xml");
Spatial alien = (Spatial) assetManager.loadModel(blenderKey);
alien.setLocalTranslation(new Vector3f(-145, 15, -10));
rootNode.attachChild(alien);
You didn't write anything about your material - did you write one and used it correctly? The problem you get seems to be the lack of material to me.
In general you'll need some *.material file and probably some textures (if you used them in Blender). For the beginning you can use one of the materials that come with Ogre, you'll just need to add:
model3.setMaterialName( "Examples/Rockwall" );
Then look if it changes anything. If you still get the problem you can look into 'Ogre.log' file - it's always worth checking because all the errors goes there.
I also see the second problem here - you render the object as 'one sided' while blender probably render is as two-sided mesh, so you get the holes on the head. You can select in the material to be two sided, but it's better (and faster during rendering) to just create your models without the holes :).