How to select and manipulate individual spatials in a .obj import?

Hello. I’ve been having some issues with the model I loaded from a .obj file extension. I need to be able to reference the component parts of this model and manipulate these parts individually. This has been my struggle for the last several hours.

To load the model itself, I simply write:

[java]Model = (Node)assetManager.loadModel(“model.obj”);[/java]

To then reference the component parts, of the model, I initially tried to do this:

[java]Spatial part = model.getChild(“Part1”);[/java]

However, this doesn’t work as it does not seem possible to reference the different spatials by the same name that I gave them in 3DS, even if their individual meshes are correct. So instead, I devised this way of doing it:

[java]Spatial part = model.getChild(7);[/java]

The above successfully retrieves the part, with the drawback that I need to trial-and-error my way to which part goes with which index. On the way, I discovered that on calling model.getChild(int), that model seemed to be removed from the list of model children. Case in point, if before a cast to model.getChild(int) I do this:

[java]System.out.println(model.getChildren().size());[/java]

It might print, say, 12. If I then call model.getChild(7) and do the print of getChildren().size() again, it returns 11. Why is this?

Then, I need to take this spatial and apply transforms to it. In order to do this, I wrap it in a node, and attach it back to the model, as such:

[java]Node partNode= new Node();
partNode.attachChild(part);
model.attachChild(partNode);[/java]

In this way I attach the spatial back to my original model in its original location. When I now try to apply a transformation to it, nothing happens. Yes, this is done in the update thread.

[java]partNode.setLocalRotation(new Quaternion().fromAngleNormalAxis(FastMath.HALF_PI-(float)Math.random()*0.05f, Vector3f.UNIT_Y));[/java]

If I simply make myself some random box and do the same thing, it works perfectly. What’s so different about my partNode?

What I want to know is; is there a “best” way of referencing component parts of a .obj model, and applying transforms to only these parts? What am I doing wrong here?

Open the model in the SDK and look bottom left at the SceneExplorer.

Tried importing the model in the IDE, but I get an out of memory exception:

[java]java.lang.OutOfMemoryError: Direct buffer memory
at java.nio.Bits.reserveMemory(Bits.java:658)
at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123)
at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:306)
at com.jme3.util.BufferUtils.createByteBuffer(BufferUtils.java:956)
at com.jme3.texture.plugins.AWTLoader.load(AWTLoader.java:163)
at com.jme3.texture.plugins.AWTLoader.load(AWTLoader.java:191)
at com.jme3.texture.plugins.AWTLoader.load(AWTLoader.java:200)
at com.jme3.asset.DesktopAssetManager.loadAsset(DesktopAssetManager.java:288)
at com.jme3.asset.DesktopAssetManager.loadTexture(DesktopAssetManager.java:346)[/java]

Trying to convert the model to .j3o seems to just run forever.

You can use a scenegraphvisitor. For example, have a look at this “generic” way to find sub-spatials.

[java]
public abstract class FindSpatialWithCondition implements SceneGraphVisitor, Filter<Spatial>
{
private List<Spatial> results;

public FindSpatialWithCondition()
{
this.results = new ArrayList<>();
}

@Override
public void visit(Spatial spatial)
{
if ( apply(spatial) )
{
this.results.add(spatial);
}
}

public Collection<Spatial> results()
{
return this.results;
}
}
[/java]

You can extend it like this :

[java]
public class FindSpatialWithRegExp extends FindSpatialWithCondition
{
private String regExp;

public FindSpatialWithRegExp(String regExp)
{
this.regExp = regExp;
}

@Override
public boolean apply(Spatial input)
{
return input.getName().matches(regExp);
}
}[/java]

then use it like this :

[java]

// theModel is the model you loaded

FindSpatialWithRegExp finder = new FindSpatialWithRegExp(".Part1.");
theModel.depthFirstTraversal(finder);

// now finder.results() will give you every spatials with “Part1” in their name
[/java]

If you want to know the exact name of your spatial in jme (you’ll find that the export and/or the import added some garbage stuff in the name, like numbers etc) you can do

[java]

//theSpatial is the spatial you found with theModel.getSpatial(7)
System.out.println(theSpatial7.getName());
[/java]

Actually, the spatial names seem to be autogenerated from the model filename. If I do this:

[java]for (Spatial spatial : model.getChildren()) System.out.println(spatial.getName());
[/java]

I get a list looking like this:

modelfilename-geom-0
modelfilename-geom-1

modelfilename-geom-21

What I don’t understand is why the importer does not use the names defined in the .obj file, but that’s not the main issue here. The issue is the peculiarities with retrieving the individual Spatials from the model as I described above.

I don’t know why you get a out of memory error, but if it’s because your model is too big you have a problem. For example, you can easily find a lot of 3D models on the internet but most of them are only for pictures and have way too much poly for real time rendering.

Also, you can try to import and save your file in blender (the last one, not the one embedded in jme), then load the .blend file instead of the .obj.

I said “the last one” because i get similar errors with the embedded blender (export trash names).

EDIT : as soon as you’ll have real names in jme it will be ok, even if these names are not exactly the ones you put. In my example i gave you a way to get all the spatial with name with “Part1” in it. In your current situation you can’t use it (because you don’t have real names, just generic garbage), but as soon as you’ll get things like GarbageWithNumber_Part1_OtherUselessGarbage it will be ok.

Yeah, the model is big, but it loads and displays just fine in the application itself. Just doesn’t want to load in the IDE. I’ve also found a way to access the different Spatials I need using model.getChild(int).

What I can’t get my head around is why I can’t manipulate these spatials directly, without first wrapping them in a separate node and attaching that node to my root. Then I can do it, but then I have two of them - the one that was already attached, and the one I just added. I also have the added problem of reattaching my now “loose” node to the model, which is another issue I haven’t been able to figure out yet.

This is where I tried to call partX.removeFromParent(), but that doesn’t work since partX apparently doesn’t exist in the parent Geometry anymore since my call to getChild(int).

I’m sure I’ll find a workaround for these issues, they’re just really confusing me at the moment.

I really think you are doing something wrong. Why you want to manipulate things as individual object if you put them together in the mesh in the first place ?
Also, the “getChild(int)” is not a reliable method if your int is hard writed in the code - as soon as you’ll add anything in your scene the int will point to a different element.

And a spatial can have only one parent. If you create new nodes and attach elements or your model to them, these elements will not be accessible from their old parent (the original model).

And about your part node, i will do something more like this :

[java]
Node partNode = new Node(“a name, dude”);

partNode.setLocalTranslation(part.getLocalTranslation());
partNode.setLocalRotation(part.getLocalRotation());

part.setLocalRotation(Quaternion.DIRECTION_Z);
part.setLocalTranslation(Vector3f.ZERO);

partNode.attachChild(part);
scene.attachChild(partNode);

[/java]

Not sure for the rotation, but it’s something like this. but, once again, i think you are doing it wrong.

@bubuche said: I really think you are doing something wrong. Why you want to manipulate things as individual object if you put them together in the mesh in the first place ? Also, the "getChild(int)" is not a reliable method if your int is hard writed in the code - as soon as you'll add anything in your scene the int will point to a different element.

And a spatial can have only one parent. If you create new nodes and attach elements or your model to them, these elements will not be accessible from their old parent (the original model).

Well, I didn’t make the model. My 3DS skills are far below what’s required to modify it without breaking it (it’s a model of a commercial ship). I want to manipulate individual parts of the ship, that’s why I grouped their geometries in 3DS and gave them a name. I’ve done the same before with a far simpler model in Blender and the above method worked in that case. Just reference the individual geometries by index or name and apply transformations to them.

Importing this model to Blender is not an option because texture information seems to be lost when I do. Again, might be my lack of 3D modelling application skills. Loading the model from .obj works fine, textures, lighting and all. So naturally it’s my preferred method so far.

I don’t see the difference between using getChild(7) and getChild(“ship-geom-7”). Adding more objects to my root node surely will not affect the ship model information, only adding more objects to the ship model node would do that (which I might have to do anyway to get this to work).

I tried to call removeFromParent() on the Spatial as extracted from the overall mesh, like this:

[java]Spatial part = model.getChild(3);
part.removeFromParent();[/java]

I’m not 100% sure this is the intended usage, I’ve never done this before. It’s a moot point anyway when the preceding call to getChild seems to flat out remove the Spatial from the model.