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!
Related
When I get a face's center Pose, its always relative to the camera. I'd like to get the Pose's location and orientation as relative to an origin Pose instead.
Here's what I've tried:
Pose centerPose = face.getCenterPose();
// set up origin neutral Pose if not done yet
if (neutralPose == null) {
neutralPose = centerPose;
}
centerPose = centerPose.compose(neutralPose.inverse());
But this is not giving me what I want - rotating the head results in major positional translations.
Using ARCore's Pose (or Anchor?), how would I do this?
I was close! The magic words are:
Pose relativePose = neutralPose.inverse().compose(centerPose);
This gives me what I want. The reason being: I need the neutral's inverse to transform the new position BACK.
I'm getting this when I load any .obj file with ObjLoader:
How it looks like in real:
How I'm loading it:
ModelInstance instance = new ModelInstance(model);
instance.transform.setToTranslation(-4, 0, 0);
instance.transform.mul(transform.setToRotation(Axis.X,(float)(Math.random()*360)));
Then in onCreate():
Gdx.gl.glClearDepthf(1.0f);
Gdx.gl.glEnable(GL20.GL_DEPTH_TEST);
Gdx.gl.glDepthFunc(GL20.GL_LESS);
Gdx.gl.glDepthRangef(0f, 1f);
Gdx.gl.glEnable(GL20.GL_TEXTURE_2D);
And in render():
Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
Gdx.gl.glClearColor(.1f, .1f, .1f, 1f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
shader.begin(camera, instances.get(i).transform);
modelBatch.begin(camera);
if (environment !=null) modelBatch.render(instances.get(i), environment, shader);
else modelBatch.render(instances.get(i), shader);
modelBatch.end();
shader.end();
Clean source code here:
source code
SOLUTION:
1, probleme was with the .mtl file, copy pasted from the ship.mtl and rewrite
2, probleme was with the camera near, and far plane (0.1 and 1000 is the good)
3, probleme was with the obj file texture, because it flipped on the obj file, solution was to convert g3db with -f
When using the libgdx 3D api (ModelBatch and/or Shader), you should not change the opengl state outside the Shader class. So, enabling/disabling depth test etc. is useless and might result in unpredicted behavior.
You should not use obj files. Instead use fbx-conv and use the g3db or g3dj file format. Also, your model is missing the mtl file, causing the material not to be applied.
You are using your own shader, you should not have to call shader.end(), modelbatch does this for you.
I tried your model (without material obviously) and it renders correctly using the default shader.
Looks more like you've some problems with your normals here. I don't think it's a problem of wrong depth. Depending on your modelling program e.g. blender3D, you could try to recalculate your facenormals and export it again!
You may follow these steps on 3D Studio Max:
Select all your design with CTRL+A (If you use Windows)
Press ALT+G to select Group category near Edit and Tools selection
Make your all work as a group
Try again on your Android application.
It should be done.
I am trying to add a Map to my libgdx app as a proof of concept. It seems that no matter how I make a packfile, the com.badlogic.gdx.graphics.g2d.tiled.TileAtlas constructor TileAtlas(TiledMap map, FileHandle inputDir) will not correctly read it. My Tile Map is simple and has only 2 tiles, and both the external gui and internal system will generate a packed file.
Here's the issue, either I name the packfile with a filename to match one of my images to satisfy line 2 below, or the method errors out. If I add 2 packfiles, one for each name of an image in my tile set, I find the Atlas isn't constructed correctly in memory. What am I missing here? Should there only ever be one tile in a tilemap?
Code from Libgdx:
for (TileSet set : map.tileSets) {
FileHandle packfile = getRelativeFileHandle(inputDir, removeExtension(set.imageName) + " packfile");
TextureAtlas textureAtlas = new TextureAtlas(packfile, packfile.parent(), false);
Array<AtlasRegion> atlasRegions = textureAtlas.findRegions(removeExtension(removePath(set.imageName)));
for (AtlasRegion reg : atlasRegions) {
regionsMap.put(reg.index + set.firstgid, reg);
if (!textures.contains(reg.getTexture())) {
textures.add(reg.getTexture());
}
}
}
com.badlogic.gdx.graphics.g2d.tiled --> It looks like you're using the old tiled API. I don't even think that package exists anymore, so you should probably download a newer version.
Check out this blog article. I haven't used the new API yet, but at a quick glance it looks much easier to load maps.
I followed this tutorial in order to try and achieve multitexturing in LWJGL. But whenever I run my code, the second texture does not show up, or the first texture takes its place. Here is how I bind the textures:
ARBMultitexture.glActiveTextureARB(ARBMultitexture.GL_TEXTURE0_ARB);
bindTexture(myTex);
glEnable(GL_TEXTURE_2D);
glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, EXTTextureEnvCombine.GL_COMBINE_EXT);
glTexEnvf (GL_TEXTURE_ENV,EXTTextureEnvCombine.GL_COMBINE_RGB_EXT, GL_REPLACE);
ARBMultitexture.glActiveTextureARB(ARBMultitexture.GL_TEXTURE1_ARB);
bindTexture(myTex2);
glEnable(GL_TEXTURE_2D);
glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, EXTTextureEnvCombine.GL_COMBINE_EXT);
glTexEnvf (GL_TEXTURE_ENV, EXTTextureEnvCombine.GL_COMBINE_RGB_EXT, GL_INCR);
drawStuff();
myTex and myTex2 both Textures, drawStuff() is my function where I draw everything.
I use slick for loading the textures and such, here is my bindTexture function:
void bindTexture(Texture t) {
glBindTexture(GL_TEXTURE_2D, t.getTextureID());
}
In drawStuff() I have a custom "Face" class, and here is where I draw everything in there:
glBegin(GL_TRIANGLES);
glNormal3f(getNormal().x, getNormal().y, getNormal().z);
glNormal3f(norm1.x, norm1.y, norm1.z);
ARBMultitexture.glMultiTexCoord2fARB(ARBMultitexture.GL_TEXTURE0_ARB, t1.x, t1.y);
ARBMultitexture.glMultiTexCoord2fARB(ARBMultitexture.GL_TEXTURE1_ARB, t1.x, t1.y);
glVertex3f(p1.x, p1.y, p1.z);
glNormal3f(norm2.x, norm2.y, norm2.z);
ARBMultitexture.glMultiTexCoord2fARB(ARBMultitexture.GL_TEXTURE0_ARB, t2.x, t2.y);
ARBMultitexture.glMultiTexCoord2fARB(ARBMultitexture.GL_TEXTURE1_ARB, t2.x, t2.y);
glVertex3f(p2.x, p2.y, p2.z);
glNormal3f(norm3.x, norm3.y, norm3.z);
ARBMultitexture.glMultiTexCoord2fARB(ARBMultitexture.GL_TEXTURE0_ARB, t3.x, t3.y);
ARBMultitexture.glMultiTexCoord2fARB(ARBMultitexture.GL_TEXTURE1_ARB, t3.x, t3.y);
glVertex3f(p3.x, p3.y, p3.z);
glEnd();
Where t1, t2, t3, norm1, norm2, norm3, p1, p2, p3 are all instances of a 3D vector class I made (I just keep a 0 in the z component of t1, t2, and t3). The vertex and fragment shader source is exactly the same as in the aforementioned tutorial.
All the code was working just fine with plain old textures. Any ideas on how I could make this work? Or possibly a better tutorial that is easy to follow when using LWJGL?
I strongly recommend you to learn from these tutorials how to use modern OpenGL with LWJGL .?If you take a look at the examples in afore mentioned link you will find your ways.I don't know how it works in fixed pipeline but using modern one it's just a matter of plugging several textures into texture targets in fragment shaders and sample those blending texels as you wish.
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 :).