Geometry Not Showing Unless clearCache called

Hey all,



Got something really weird going on… in the Gentrieve 2 map system, I make small transparent boxes for each room. If a room is a “special” room, like a Save Room, or Starting Room, I want a small label to be placed in the center of the room. I got this working when I was drawing the entire map all the time – all of my labels showed up OK. However, when I reduced the map to only discovered areas, I noticed some of my labels were not showing up properly. In this picture, the room with the green arrow (the room the player is in), should have a Save Room label:



http://i.imgur.com/Vqhhu.png



You can see the “Starting Room” label renders fine. Here is the code for adding labels to rooms:



[java] // make some kinda label in this room?

String useTexture = null;

if( forRoom.BossAbility != null ) {

useTexture = “Textures/bossroom.png”;

} else if( forRoom.SpecialType != null ) {

if( forRoom.SpecialType.startsWith(“SecretRoom”) ) {

useTexture = “Textures/itemroom.png”;

} else {

useTexture = “Textures/itm” + forRoom.SpecialType.toLowerCase() + “.png”; // useTexture gets set to “Textures/itmsaveroom.png” here

}

} else if( forRoom.roomsFromStart == 0 ) {

useTexture = “Textures/startroom.png”;

}

if( useTexture != null ) {

Geometry roomlabel = new Geometry(“map_label”, Main.SimpleQuad);

Material mat = new Material(Main.GApp.getAssetManager(), “Common/MatDefs/Misc/Unshaded.j3md”);

//((DesktopAssetManager)Main.GApp.getAssetManager()).clearCache();

mat.setTexture(“ColorMap”, Main.GApp.getAssetManager().loadTexture(useTexture));

roomlabel.addControl(new BillboardControl());

mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);

mat.getAdditionalRenderState().setDepthWrite(false);

roomlabel.setQueueBucket(Bucket.Transparent);

roomlabel.setMaterial(mat);

roomlabel.setLocalTranslation(forRoom.GetSizeX()ROOM_SCALE0.5f,

forRoom.GetSizeY()ROOM_SCALE0.5f,

forRoom.GetSizeZ()ROOM_SCALE0.5f);

BaseNode.attachChild(roomlabel);

}

[/java]



If I un-comment out the getAssetManager().clearCache() line, this happens (which is what it is suppose to look like):



http://i.imgur.com/7jCHh.png



I thought of trying the clearCache() because when stepping through the program, I saw it getting “Textures/itmsaveroom.png” from some smartcache. However, I’m pretty sure this is the first place I try and load itmsaveroom.png, so I wasn’t sure at what point it was caching it from… when the cache is cleared, the texture is not in the cache, and the Save Room label displays OK.



Any ideas? Any help would be appreciated… I don’t want to clear the whole cache if I don’t need to :confused:



P.S. I’ve also tried attaching my map system to the built-in rootNode, to see if it was at all related, but this same behavior still happens (just incase you’ve read my other threads, hehe).

Tryx add a system.out when a texture with taht name is added to the smart cache. Sounds kinda strange tho, even if it is cached, it should be identicallt to the one you load from disk. (thats the whole point of the cache at least)

Nightly or Stable?

This is in the nightly.



I found out where the texture was getting loaded and put into cache:



When I enter the save room, the texture gets loaded to create a 3D floppy disk model from the 2D texture image. This is why the Start Room label works fine – it doesn’t get loaded earlier to be made into a 3D model for the room. This also explains why all the labels worked fine when all the rooms were displayed immediately – because I didn’t enter the rooms, and the code above WAS the first place the texture got loaded and cached. If the texture gets loaded and cached via my 2D to 3D modeling code, it breaks future cached versions… this is the code that loads the 2D texture for 3D modeling:



[java] private void MakeItemModel() {

Texture centerTex = Main.GApp.getAssetManager().loadTexture(“Textures/itm” + Name.toLowerCase() + “.png”);

if( centerTex == null ) return;

if( GeometryCache.containsKey(Name) ) {

CenterItem = ((Geometry)GeometryCache.get(Name)).clone(false);

} else {

float sidetex, width;

sidetex = 0.025f;

if( Name.equals(“Health”) ||

Name.equals(“HealthRoom”) ) {

width = 0.05f;

} else {

width = 0.1f;

}

CenterItem = GImageToModel.Create(centerTex, Main.GApp.getAssetManager(), width, 32, sidetex);

GeometryCache.put(Name, CenterItem);

}

…[/java]



This is where centerTex gets used in GImageToModel:



[java] public static Geometry Create(Texture sourcetex, AssetManager assetManager, float thickness, int alphaThreshold, float sideTextureWidth,

float centerXPercent, float centerYPercent) {

BufferedImage source = ImageToAwt.convert(sourcetex.getImage(), false, true, 0);

AffineTransform tx = AffineTransform.getScaleInstance(1, -1);

tx.translate(0, -source.getHeight(null));

AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);

source = op.filter(source, null);

…[/java]



If I comment-out that AffineTransform code (which flips the BufferedImage), the problem still happens…



Still not sure why this is happening, but at least I found a bit more info… :confused:

More info:



Inside my GImageToModel.Create code, I also do this to the texture:



[java] sourcetex.setMagFilter(Texture.MagFilter.Nearest);

sourcetex.setMinFilter(Texture.MinFilter.NearestNoMipMaps);[/java]



… which if I comment out, the problem goes away! However, I want my textures to have no mipmaps / smoothing on the 3D model, so I don’t want to remove these lines… but why would this mess up the cache?



I then tried setting the MagFilter and MinFilter to Nearest(NoMipMaps) during room label creation:



[java] if( useTexture != null ) {

Geometry roomlabel = new Geometry(“map_label”, Main.SimpleQuad);

Material mat = new Material(Main.GApp.getAssetManager(), “Common/MatDefs/Misc/Unshaded.j3md”);

Texture tex = Main.GApp.getAssetManager().loadTexture(useTexture);

tex.setMagFilter(Texture.MagFilter.Nearest);

tex.setMinFilter(Texture.MinFilter.NearestNoMipMaps);

mat.setTexture(“ColorMap”, tex);

roomlabel.addControl(new BillboardControl());

mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);

mat.getAdditionalRenderState().setDepthWrite(false);

roomlabel.setQueueBucket(Bucket.Transparent);

roomlabel.setMaterial(mat);

roomlabel.setLocalTranslation(forRoom.GetSizeX()ROOM_SCALE0.5f,

forRoom.GetSizeY()ROOM_SCALE0.5f,

forRoom.GetSizeZ()ROOM_SCALE0.5f);

BaseNode.attachChild(roomlabel);

}[/java]



… and it works! The floppy disk shows up in the room as expected, without any cache clearing. Granted the floppy disk doesn’t have any mip maps or smoothing, but it is at least there. :slight_smile: I guess something breaks if you change the Min/Mag filter on the first load of a texture, and you don’t use that same Min/Mag filter combination later? :?

If you change the file as it comes from the assetmanager it would make very much sense its taken out of the cache as this is not what the assetManager wants to provide. Is there a special reason you do all that caching and cloning? The assetManager does that for you for loaded models…? It might be easier to just prepare all the data in j3m or j3o form (which would then automatically be cached)?

I do the GeometryCache stuff because I create 3D models via code from the 2D images (so I don’t have to do any 3D modeling, which I’m pretty bad at). I cache the final 3D model once it is generated and clone it out as it is requested. The 3D object created renders fine inside my room. It is the room label in the map, which is a 2D quad using the same texture, that doesn’t render correctly after that texture was read to make the 3D object inside the room, and I set the originally loaded texture’s Mag/Min filter to Nearest/NoMipMaps. I kinda sorta resolved this for the time being by making my 2D room label also Nearest/NoMipMaps, but I don’t really understand why that “fixes” it :stuck_out_tongue:

As said. The assetManager gives you a certain image with certain configuration when you use it. If you change that image then it cannot be used as the cache anymore as the assetManager would then return an image that is different than the “normal” image it should return. You would “break” the assetManager for other parts of the game. Ofc for you this wouldn’t matter but in general that would be inconsistent behavior.

You could clone the image before processing it, or use a custom texturekey that disables the smartcache when loading it.

So to understand this issue a bit more, I made a test case. In the first test case, I only modify the second texture, and it works as I’d expect it to:



http://i.imgur.com/EKPKo.png



[java] public void simpleInitApp() {

Box b = new Box(Vector3f.ZERO, 1, 1, 1); // create cube shape at the origin

Geometry geom = new Geometry(“Box”, b); // create cube geometry from the shape

Texture tex1 = assetManager.loadTexture(“Textures/ColoredTex/Monkey.png”);

Material mat = new Material(assetManager,

“Common/MatDefs/Misc/Unshaded.j3md”); // create a simple material

mat.setTexture(“ColorMap”, tex1);

geom.setMaterial(mat); // set the cube’s material

rootNode.attachChild(geom); // make the cube appear in the scene



Geometry geom2 = new Geometry(“Box2”, b);

Texture tex2 = assetManager.loadTexture(“Textures/ColoredTex/Monkey.png”);

tex2.setMagFilter(Texture.MagFilter.Nearest);

tex2.setMinFilter(Texture.MinFilter.NearestNoMipMaps);

geom2.setLocalTranslation(3f, 0f, 0f);

Material mat2 = new Material(assetManager,

“Common/MatDefs/Misc/Unshaded.j3md”); // create a simple material

mat2.setTexture(“ColorMap”, tex2);

geom2.setMaterial(mat2); // set the cube’s material

rootNode.attachChild(geom2); // make the cube appear in the scene



}

[/java]



In this next test case, I modify the first texture – this causes the second box to disappear:



http://i.imgur.com/YBeoG.png



[java] public void simpleInitApp() {

Box b = new Box(Vector3f.ZERO, 1, 1, 1); // create cube shape at the origin

Geometry geom = new Geometry(“Box”, b); // create cube geometry from the shape

Texture tex1 = assetManager.loadTexture(“Textures/ColoredTex/Monkey.png”);

tex1.setMagFilter(Texture.MagFilter.Nearest);

tex1.setMinFilter(Texture.MinFilter.NearestNoMipMaps);

Material mat = new Material(assetManager,

“Common/MatDefs/Misc/Unshaded.j3md”); // create a simple material

mat.setTexture(“ColorMap”, tex1);

geom.setMaterial(mat); // set the cube’s material

rootNode.attachChild(geom); // make the cube appear in the scene



Geometry geom2 = new Geometry(“Box2”, b);

Texture tex2 = assetManager.loadTexture(“Textures/ColoredTex/Monkey.png”);

geom2.setLocalTranslation(3f, 0f, 0f);

Material mat2 = new Material(assetManager,

“Common/MatDefs/Misc/Unshaded.j3md”); // create a simple material

mat2.setTexture(“ColorMap”, tex2);

geom2.setMaterial(mat2); // set the cube’s material

rootNode.attachChild(geom2); // make the cube appear in the scene



}[/java]



From what I understand, when I change the Min/Mag filter on the first texture, I am messing up the cached copy. However, when modifying the second texture, I am just modifying a clone of the cached texture, so it works OK. Correct? At any rate, I found this to be sneaky behavior… :confused:

1 Like

There might be a bug there somewhere, thanks for the test case.

1 Like

OK, the bug was fixed. Thanks for the report.

1 Like