I'm trying to add a 2D overlay for a 3D scene in Java3D, part of this overlay is to draw a line from a 2D object to a corresponding point in the 3D scene...
Searched transformation from 3D to 2D and read those threads:
Translate Java 3D coordinates to 2D screen coordinates
3D to 2D projection
from code inside walrus:
https://github.com/CAIDA/walrus/blob/master/H3ViewParameters.java
copied a method to a class extending Canvas3D:
public Transform3D getObjectToEyeTransform() {
Point3d m_eye = new Point3d();
getCenterEyeInImagePlate(m_eye);
Transform3D m_imageToEye = new Transform3D();
m_imageToEye.set(new Vector3d(-m_eye.x, -m_eye.y, 0.0));
Transform3D m_vworldToImage = new Transform3D();
getVworldToImagePlate(m_vworldToImage);
Transform3D transform = new Transform3D(m_imageToEye);
transform.mul(m_vworldToImage);
//transform.mul(m_objectTransform);
return transform;
}
and then in my overlay in method postRender i try to do the following:
Transform3D viewTrans3d = getObjectToEyeTransform();
Vector3d point = new Vector3d(1,1,1);
viewTrans3d.invert();
viewTrans3d.transform(point);
this.getGraphics2D().drawLine(0, 0, (int)point.x, (int)point.y);
Getting very weird line, which do change in a quite logical pattern (when i rotate and tilt the view) but far from what i expect...
Questions:
commented the m_objectTransform matrix multiplication because i
don't understand its purpose, any idea?
Why do i need to invert the transform matrix? without the invert the results are even weirder...
Is there a simpler way to do this??? sounds like something solved eons ago...
This can be done by using getVworldToImagePlate and then getPixelLocationFromImagePlate in the Canvas3D class. For example:
public Point2d getPosition2d(Point3d point) {
Transform3D transform = new Transform3D();
getVworldToImagePlate(transform);
transform.mul(objectTransform);
Point3d newPoint = new Point3d(point);
transform.transform(newPoint);
Point2d point2d = new Point2d();
getPixelLocationFromImagePlate(newPoint, point2d);
return point2d;
}
The objectTransform variable should be the transform of any TransformGroup in the scene that is applied to the 3d objects that are displayed. If you don't have any TransformGroup, then you can leave this out. Also, the transform shouldn't be inverted, just use it as it is.
Related
In netbeans, there is an option under samples called CubeSystem3D. I was wondering if there was a way to convert all of the cubes to spheres so I can eventually create a solar system type of thing. I can send the actual code if you are unable to retrieve it off netbeans because I can not put the code of this post as it says there will be too much code compared with text.
Use below Ellipse class instead of Cube class in that neabeans sample code.
public class Ellipse extends Group {
final Rotate rx = new Rotate(0, Rotate.X_AXIS);
final Rotate ry = new Rotate(0, Rotate.Y_AXIS);
final Rotate rz = new Rotate(0, Rotate.Z_AXIS);
public Ellipse(double size, Color color, double shade) {
PhongMaterial material = new PhongMaterial();
material.setDiffuseColor(color);
material.setSpecularColor(Color.BLACK);
getTransforms().addAll(rz, ry, rx);
Sphere s = new Sphere(size);
s.setMaterial(material);
getChildren().addAll(s);
}
}
You will get something like this,
I have an application, where all scene objects are loaded from .obj files (they are exported from Blender). And I need to rotate one of this objects around specific point. Currently, I have the following code:
public void rotateTo() {
// translate to origin, rotate, translate back
Vector3f origin = new Vector3f();
Vector3f pivot = new Vector3f(.0f, .5f, .0f);
this.getTransform(this.transform);
this.transform.get(origin);
double angle = -Math.PI / 2;
double newX = origin.getX() + Math.cos(angle) * (pivot.getX() - origin.getX()) - Math.sin(angle) * (pivot.getY() - origin.getY());
double newY = origin.getY() + Math.sin(angle) * (pivot.getX() - origin.getX()) + Math.cos(angle) * (pivot.getY() - origin.getY());
this.transform.set(new Vector3f((float)newX, (float)newY, .0f), 0.15f);
this.setTransform(this.transform);
this.transform.set(origin, 0.15f);
this.setTransform(this.transform);
}
Where this refers to TransformGroup object, that I need to rotate, and this.transform refers to Transform3D object.
But this method doesn't work as I expected. I have also tried this and this solutions, but they also didn't work for me.
I think, maybe, try to perform this manipulation with the help of GeometryArray, but I can't understand, how to do this. Also, I can try to export my objects with different origin points, but it's not clean solution, I think, because then I would need to move them to right positions with code.
Here's my object:
I'm trying to rotate it around green point, but in all cases it rotates around red point, or doesn't rotate at all, or translates to some point without rotation.
P.S. I know, that Java3D is an old library and can use more powerful tools, but it's my university professor's requirement and I can't refuse using it.
Composition of transformations can be achieved using matrix multiplication. Below is an example that rotates a cube 180° about the X axis with the pivot at the centre of its top face.
There are three steps as mentioned in the question: translate so that the pivot is at the origin, rotate, and translate back. Comment out steps to see what is happening.
With all steps commented out, the box appears at the centre with its red side facing forward.
Uncomment the first step. The box shifts down so its top is at the centre of the screen.
Uncomment the second step. The box rotates about the X axis (the left-right axis, through the top of the box). The green side now faces forward, and the bottom of the box is now at the centre of the screen.
Uncomment the third step. The box shifts up, and the overall effect is that it rotated about a left-right axis through its top face.
The application of a transformation T to a vector v is defined as T*v in Java 3D, so the composition of two transformations T and U where T is to be done first and U is to be done second is U*T. Note how the order is reversed. In general, the composition of the transformations T1, T2, ..., Tn where T1 is done first and Tn is done last is Tn*...*T2*T1.
This can be expressed in Java 3D using the following pattern:
Transform3D t1 = ..., t2 = ..., t3 = ...;
// first do t1, then t2, then t3
Transform3D all = new Transform3D(); // all = identity
all.mul(t1, all); // all = t1 * all
all.mul(t2, all); // all = t2 * all
all.mul(t3, all); // all = t3 * all
// now all == t3 * t2 * t1
Methods such as Transform3D.set(Vector3d,double) and TransformGroup.setTransform() overwrite the existing transformation rather than compose with it, which is one of the reasons your code does not work.
I found the article http://www.developer.com/java/other/article.php/3717101/Understanding-Transforms-in-Java-3D.htm helpful.
// based on http://www.java3d.org/starting.html
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.universe.SimpleUniverse;
import javax.media.j3d.*;
import javax.vecmath.*;
public class Demo
{
public Demo() {
SimpleUniverse universe = new SimpleUniverse();
BranchGroup group = new BranchGroup();
group.addChild(createModel());
universe.getViewingPlatform().setNominalViewingTransform();
universe.addBranchGraph(group);
}
Node createModel() {
double radius = 0.3;
ColorCube cube = new ColorCube(radius);
// rotation of cube about the center of the top face
// i.e. the point (x=0, y=radius, z=0)
Transform3D transform = new Transform3D();
// step 1: translate cube down so that (0, radius, 0) is at the origin
Transform3D translate1 = new Transform3D();
translate1.setTranslation(new Vector3d(0.0, -radius, 0.0));
transform.mul(translate1, transform);
// step 2: rotate cube about X axis by 180 degrees
Transform3D rotate = new Transform3D();
rotate.rotX(Math.PI);
transform.mul(rotate, transform);
// step 3: translate cube back up
Transform3D translate2 = new Transform3D();
translate2.setTranslation(new Vector3d(0.0, +radius, 0.0));
transform.mul(translate2, transform);
// create a TransformGroup
TransformGroup tg = new TransformGroup();
tg.setTransform(transform);
tg.addChild(cube);
return tg;
}
public static void main(String[] args) {
new Demo();
}
}
I have a very simple Java3D application, it contains two cubes, of which one of them orbits the other.
Like so:
As you can see, the default position for the viewing platform is from a 'kind of' birds eye view.
The code that looks like so
TransformGroup cameraTG = u.getViewingPlatform().
getViewPlatformTransform();
Vector3f translate = new Vector3f();
Transform3D T3D = new Transform3D();
translate.set( 0.0f, 0.0f, 20.0f);
T3D.setTranslation(translate);
cameraTG.setTransform(T3D);
My question is, is it possible to set the viewing platform to track the larger cube (the cube that rotates around the smaller square). Or more straight forward, is it possible for the viewing platform to rotate around a given body?
More information:
My goal is to have a miniature solar system, containing the Sun, Earth and moon. And I would like to view it from the point of view of the earth (almost like a view from the ISS)
Any help or pointers would be fantastic. Please feel free to ask for more information if needed.
You have a nice example here http://java3d.nl/Tutorials/Java/Java3d/Controlthecamera_12.php
The original http://java3d.nl website is no longer available, but you can still use the cached version from the Internet Archive: https://web.archive.org/web/20131218022035/http://java3d.nl/Tutorials/Java/Java3d/Controlthecamera_12.php
this.camera = this.universe.getViewingPlatform().getViewPlatformTransform();
//Add things to the universe
this.root = new BranchGroup();
this.root.addChild(new ColorCube(0.2));
this.universe.addBranchGraph(root);
My idea is like this:
BranchGroup b=new BranchGroup();
b.addChild(cube);
b.addChild(camera);
then in a loop where you rotate the block:
while(true) {
... b.getChild()......... etc
apply transform
}
or more specifically
for(j=0; j<group.numChildren(); j++) {
Node ni=group.getChild(j);
if(ni instanceof TransformGroup) {
Transform3D tdi=new Transform3D();
TransformGroup tgi=(TransformGroup)group.getChild(j);
tgi.getTransform(tdi);
Transform3D rotation = new Transform3D();
rotation.rotX(Math.toRadians(0.001*i));
tdi.mul(rotation);
tgi.setTransform(tdi);
}
}
There is a simpler solution. Instaed of trying to control the viewer gaze using angles and rotation, you can merely say what 3D point to look at. In the ViewingTransform, you can call "lookAt(...)":
TransformGroup viewingTransformGroup = simpleUniv.getViewingPlatform().getViewPlatformTransform();
Transform3D viewingTransform = new Transform3D();
Point3d eye = viewersLocation;
Point3d center = gazePoint;
Vector3d up = new Vector3d(0,1,0); //assumes +y-axis points up
viewingTransform.lookAt(eye, center, up);
viewingTransform.invert();
viewingTransformGroup.setTransform(viewingTransform);
im stuck with something here.
Ive been trying to create a polygon shape with Libgdx and the in built Box2d classes.
my codes are the following. I create 8 vectors in an array and draw the object. the polygone shape starts at (82,0) of world coordinates.
Vector2[] vertices = new Vector2[8];
vertices[0] = new Vector2(82f , 0f );
vertices[1] = new Vector2(146f , 40f );
vertices[2] = new Vector2(385f , 268f);
vertices[3] = new Vector2(322f , 341f);
vertices[4] = new Vector2(225f , 322f);
vertices[5] = new Vector2(282f , 398f);
vertices[6] = new Vector2(161f , 457f);
vertices[7] = new Vector2(135f , 298f);
PolygonShape shape = new PolygonShape();
shape.set(vertices);
the shape im getting is this:
and thats fine, but the circle shape cant detect any collision on the sides of that object ?!?!!
any tips ?
For a start your vectors are using values which are enormous in terms of what Box2D normally works with.
http://box2d.org/2011/12/pixels/
Try scaling things down and using a world-to-screen conversion i.e.
http://www.box2d.org/forum/viewtopic.php?f=3&t=8198
Apply same group index to each shape in the world
fixtureDef.filter.groupIndex = 0;
The reason is your shape is concave i.e. it has a cut into it. Box2d only detects collisions with convex polygons.
I think it can be done by applying the transformation matrix of the scenegraph to z-normal (0, 0, 1), but it doesn't work. My code goes like this:
Vector3f toScreenVector = new Vector3f(0, 0, 1);
Transform3D t3d = new Transform3D();
tg.getTransform(t3d); //tg is Transform Group of all objects in a scene
t3d.transform(toScreenVector);
Then I tried something like this too:
Point3d eyePos = new Point3d();
Point3d mousePos = new Point3d();
canvas.getCenterEyeInImagePlate(eyePos);
canvas.getPixelLocationInImagePlate(new Point2d(Main.WIDTH/2, Main.HEIGHT/2), mousePos); //Main is the class for main window.
Transform3D motion = new Transform3D();
canvas.getImagePlateToVworld(motion);
motion.transform(eyePos);
motion.transform(mousePos);
Vector3d toScreenVector = new Vector3f(eyePos);
toScreenVector.sub(mousePos);
toScreenVector.normalize();
But still this doesn't work correctly. I think there must be an easy way to create such vector. Do you know what's wrong with my code or better way to do so?
If I get this right, you want a vector that is normal to the screen plane, but in world coordinates?
In that case you want to INVERT the transformation from World -> Screen and do Screen -> World of (0,0,-1) or (0,0,1) depending on which axis the screen points down.
Since the ModelView matrix is just a rotation matrix (ignoring the homogeneous transformation part), you can simply pull this out by taking the transpose of the rotational part, or simple reading in the bottom row - as this transposes onto the Z coordinate column under transposition.
Yes, you got my question right. Sorry that I was a little bit confused yesterday. Now I have corrected the code by following your suggestion and mixing two pieces of code in the question together:
Vector3f toScreenVector = new Vector3f(0, 0, 1);
Transform3D t3d = new Transform3D();
canvas.getImagePlateToVworld(t3d);
t3d.transform(toScreenVector);
tg.getTransform(t3d); //tg is Transform Group of all objects in a scene
t3d.transform(toScreenVector);
Thank you.