I don't know if it's relevant, but I also had a lot of difficulty (in fact, I failed) trying to replace a texture state on a Collada model. Even clearing the states of everything in the tree, then setting a texture state on the base of the model tree didn't make any difference. Could it be that setting any render states on collada models is broken somehow?
Once a collada model is converted to .jme and loaded into your app, it is no different than any other spatial in jME.
Yeah that's exactly what I thought too, so it must just be me being stupid, but I recursively scanned the tree starting from the imported node, and cleared all render states, and it STILL had the texture. I'll have another look at it when I go back to using Collada. It just reminded me when mud2005 mentioned setting materials and seeing nothing happen, since I spent an afternoon doing the same
After clearing the states did you updateRenderState on the node?
actually i did do that here is my code for loading collada
public class TestColladaLoading extends SimpleGame {
public static void main(String[] args) {
TestColladaLoading app = new TestColladaLoading();
app.setDialogBehaviour(AbstractGame.ALWAYS_SHOW_PROPS_DIALOG);
app.start();
}
protected void simpleInitGame() {
// Our model is Z up so orient the camera properly.
cam.setAxes(new Vector3f(-1, 0, 0), new Vector3f(0, 0, 1),
new Vector3f(0, 1, 0));
cam.setLocation(new Vector3f(0, -20, 20));
input = new FirstPersonHandler(cam, 80, 1);
// url to the location of the model's textures
URL url = TestColladaLoading.class.getClassLoader().getResource("");
// this stream points to the model itself.
InputStream mobboss = TestColladaLoading.class.getClassLoader()
.getResourceAsStream("test2.43.dae");
if (mobboss == null) {
System.out
.println("Unable to find file, did you include jme-test.jar in classpath?");
System.exit(0);
}
// tell the importer to load the mob boss
ColladaImporter.load(mobboss, url, "model");
// we can then retrieve the skin from the importer as well as the
// skeleton
Node model = ColladaImporter.getModel();
ColladaImporter.cleanUp();
model.clearRenderState(RenderState.RS_MATERIAL);
model.updateRenderState();
MaterialState ms = display.getRenderer().createMaterialState();
ms.setShininess(90);
ms.setSpecular(ColorRGBA.black);
ms.setEmissive(ColorRGBA.black);
ms.setAmbient(ColorRGBA.black);
ms.setDiffuse(ColorRGBA.black);
model.setRenderState(ms);
model.updateRenderState();
rootNode.attachChild(model);
rootNode.updateGeometricState(0, true);
cam.lookAt(model.getLocalTranslation(), new Vector3f(0, 1, 0));
lightState.detachAll();
PointLight pl = new PointLight();
pl.setAmbient(new ColorRGBA(1, 1, 1, 1));
pl.setDiffuse(new ColorRGBA(1, 1, 1, 1));
pl.setLocation(new Vector3f(10, 50, 200));
pl.setEnabled(true);
lightState.attach(pl);
lightState.setSeparateSpecular(true);
rootNode.updateRenderState();
}
}
clearRenderState will only clear it at the level of the Node, not it's children. To do what you are trying to do, you'll need to write a simple recursive method that clears the state from a given Spatial, and then if that Spatial is a Node, recursively calls itself passing in each of the children.
What do you think about adding a method to Node to support this? I'm not sure how many people would use it though…clearing a render state from a Node and all children would probably not be something you'd normally do is it?
Might be worth it. It would have to be at the Spatial level, and overriden at Node. Generally though, I'd recommend preparing your model in development so that by the time the user got it, it was in the exact state you want it to be in.
Unless of course you want to be able to provide that changeability in the game itself. For example, you might use something like this for skinning couldn't you?
I did the recursive clearing, then I update render state on the root node before starting the game, so hopefully that should cover it? I've definitely forgotten updateRenderState lots of times before ;(
As far as preparing models - that is fine as long as the format, and the modeller, and all converters support all the features, but that sometimes isn't the case I'll have to see if blender no-mipmapping setting carries through all the way to jME, it may well do
Stuff like shaders would be hard starting from blender as well (I think).
The thing for clearing all children's states… Maybe instead of that, just a simple piece of code that will accept a root Node, traverse children in a well defined order, and call back to a "NodeAction" interface with a method "actOnNode(Node node)" with each node it passes to, in turn. Then you could have a NodeAction called NodeRenderStateClearer that implemented actOnNode(Node node){node.clearRenderState()}. Or another one that printed the node tree, etc. I guess you could have an "indentLevel" parameter to actOnNode so that a printing routine could use that, or a NodeAction could operate only at a few levels of recursion. I can't think of anything else you would want to do with nodes, but NodeAction would make it easy! Maybe something for resetting scales, or translations etc. The code to actually implement the traversal could be in Node and Spatial (applyActionFromHere(NodeAction action) maybe?) or could be in a separate NodeTraverser, with a method applyActionFromNode(Node rootNode, NodeAction action). I'm pretty sure it's the "Visitor" pattern, but I always get them mixed up.
In fact, I think I will go rewrite my code that way, anyway. I have a few different bits of code that would be much neater that way.
well I did the recursive clearing and still no specular reflection, I just tried loading an md5 also and couldnt get specular on that either Im starting to wonder if its possible :?
edit: whew, I finally got a clue as to whats going on. I moved the camera inside the model and realized the reflections are on the INSIDE of the model. how do I get them on outside??
edit again: well it looks like the normals are backwards, i tried flipping them in blender but they always come out backward.
mud2005 said:
...I am also getting a huge fps increase with setSeperateSpecular set to true. I get 70+ compared to only 27+ with it set to false. seems strange that adding specular lighting would increase the fps I would think it would decrease. shows how much I know.
edit: I just tested without shadows and am getting 100+ fps with setSeperateSpecular(true) and 30+ fps otherwise.
Does anyone have any thoughts on this? I'm curious because it does seem a little counter-intuitive to me.
Does anyone have any thoughts on this? I'm curious because it does seem a little counter-intuitive to me.
I made a test class to re-create this problem. Im getting about 10 fps faster with setSeperateSpecular(true) in test. It may have something to do with shadows, if I remove the shadow pass there is no difference in fps. also if I remove texture from floor there is no difference in fps. Seems when a shadow is cast from model to textured floor the problem occurs.
public class TestObjJmeWrite extends SimpleGame {
TriMesh[] model = new TriMesh[100];
private BasicPassManager pManager;
private static ShadowedRenderPass sPass = new ShadowedRenderPass();
public static void main(String[] args) {
TestObjJmeWrite app = new TestObjJmeWrite();
app
.setDialogBehaviour(AbstractGame.FIRSTRUN_OR_NOCONFIGFILE_SHOW_PROPS_DIALOG);
app.start();
}
public TestObjJmeWrite(){
stencilBits = 4;
}
public void simpleUpdate(){
pManager.updatePasses(tpf);
}
public void simpleRender(){
Renderer r = display.getRenderer();
r.clearStatistics();
r.clearBuffers();
pManager.renderPasses(r);
}
protected void simpleInitGame() {
rootNode.setRenderQueueMode(Renderer.QUEUE_OPAQUE);
final URL url;
url = this.getClass().getClassLoader().getResource("ball_auv.tga");
TextureState TS2 = display.getRenderer().createTextureState();
final Texture t2 = TextureManager.loadTexture(url, Texture.MM_LINEAR,
Texture.FM_LINEAR);
t2.setWrap(Texture.WM_WRAP_S_WRAP_T);
t2.setScale(new Vector3f(7f, 1f, 1f));
TS2.setTexture(t2);
Box floorBox = new Box("box", new Vector3f(), 100, 1f, 100);
floorBox.setModelBound(new BoundingBox());
floorBox.updateModelBound();
floorBox.getLocalTranslation().set(0, -2, 0);
floorBox.updateGeometricState(0, false);
//floorBox.setRenderState(TS2);
rootNode.attachChild(floorBox);
pManager = new BasicPassManager();
sPass.add(rootNode);
ObjToJme converter = new ObjToJme();
try {
URL objFile = TestObjJmeWrite.class.getClassLoader().getResource(
"bowlingBallSwirlHoles.obj");
converter.setProperty("mtllib", objFile);
ByteArrayOutputStream BO = new ByteArrayOutputStream();
System.out.println("Starting to convert .obj to .jme");
converter.convert(objFile.openStream(), BO);
for (int x = 0; x < 20; x++) {
model[x] = (TriMesh) BinaryImporter.getInstance().load(
new ByteArrayInputStream(BO.toByteArray()));
model[x].getLocalTranslation().x += x;
model[x].updateGeometricState(0, false);
sPass.addOccluder(model[x]);
rootNode.attachChild(model[x]);
}
} catch (IOException e) {
e.printStackTrace();
}
sPass.setRenderShadows(true);
sPass.setLightingMethod(ShadowedRenderPass.MODULATIVE);
pManager.add(sPass);
display.getRenderer().setBackgroundColor(ColorRGBA.gray);
input = new FirstPersonHandler(cam, 3, 1);
lightState.detachAll();
PointLight pl = new PointLight();
pl.setAmbient(new ColorRGBA(1, 1, 1, 1));
pl.setDiffuse(new ColorRGBA(1, 1, 1, 1));
pl.setLocation(new Vector3f(0, 50, 0));
pl.setEnabled(true);
pl.setShadowCaster(true);
lightState.attach(pl);
lightState.setSeparateSpecular(false);
rootNode.updateGeometricState(0, false);
rootNode.updateRenderState();
}
}
on topic of model normals I made a couple screenshots to show problem. I exported a sphere as collada and as .obj.
First pic is collada second is .obj. I also exported a box as md5(third pic, ignore the crappy texture).
blender version 2.43
specular reflaections work on the .obj but not on the collada or md5.
seems the collada just has mini normals, is this a bug in the collada/blender export? The exported md5 also and had a different issue of flipped normals, is that also an export script issue? :?
EDIT: on the md5 issue, the flipped normals was fixed in blender, seems I didnt save the file before exporting so the normal flipping wasnt getting applied
Normals do not have a length in reality, just a direction… The size of the normals in the debugger is relative to the size of the bounding volume it has. This allows them to be visible even if the model is really big, and it allows them to not overwhelm the model if the model is really small. If it doesn't have a bounding volume, it will use a fixed value for length.
My guess is your right side picture is of a model with no BoundingVolume set. Also there are a lot more normals on that model because the collada importer automatically merges vertices that have the same location, uv coords and color, decreasing the foot print of your model. (The tool code that does this could be called by the other model loaders too, btw.)
As for the specular, it may be an export/import issue with materials? Maybe you could post your collada file for us to test.
here is ultra simple model I made to test: http://de2005.home.comcast.net/collada.zip
its a cube with a red material and white specular color, when I export it as .obj the reflection is there but not when exported as collada. I tried tweaking the material in the file but the only noticable effect was changing the colors, I still couldnt get shiny.
I thought I’d implement that system for recursively acting on a tree of Nodes/Spatials, since I found about 6 places in my code that I had nearly identical recursive functions, so here it is:
http://captiveimagination.com/svn/public/cigame/trunk/src/com/captiveimagination/game/spatial/
The main class is SpatialWalker, have a look at SpatialWalker.printSpatialTree for a simple example. It’s all pretty trivial, but it’s nice to have it in one place.
SpatialRenderStateClearer implements the render state clearing I was using on my models to try to get rid of the textures. Is there an easier way to clear all render states, other than clearing them type by type?