2

I have created a simple model of a box and created a color interpolation image using a texture map. I exported the model to fxml using the code found at

FXML export code

I have a jpeg of the colored model I tried to export and the resulting imported model, but I am new to Stack Overflow and I am not allow to post images yet.

I also could not find a way to attach the content of the FXML file that was exported, but I would be happy to share it.

When I import the fxml file back into my application using the standard FXMLLoader, the color mapping is not visible. I don't know if the export was incomplete or the import was incorrect. The FXML file appears to have the correct mesh and texture map pointers, but I don't see a representation of the texture map. I used the PhongMaterial setDiffuseMap method to assign an image to the material object that was constructed using an WritableImage and PixelWriter to create a band of colors. Does anyone know whether export of the PhongMaterial object constructed in this way is supported in the FXMLExporter or if the FXMLImporter does not support importing such a color map?

Based on the suggestions from Jose I made changes to my code, but I encountered some issues.

I defined each face of my two cubes as a separate TriangleMesh, thinking that eventually I want to be able to distinguish each face when selecting objects in the scene. I have a single PhongMaterial object that has the image as a diffuse map. I have assigned the same material to each face of my two cubes.

When I export my model, the export method tries to write the image file 12 times. It seems there should be a way to convey to the model definition that a single phong material is being used and it is based on a single color image.

I added code to the export method to remember the filename used to export the FXML file so that I could assign a name to the image file based on the FXML filename (full pathname passed to exportImage()). Without a path, the image file is stored inside my Eclipse workspace instead of in the same folder as my FXML file. I am not sure what name should be given to fxmlImage.addProperty("url",filename). Should it be the full path name or just the filename? If I use the full pathname, then I have a hardcoded path inside the FXML file and that seems like a bad idea. I tried saving the URL name with and without the full path and got the same result both ways... which was that no model appeared when I imported the FXML file. I also tried with and without the leading @, with the same result. Does anyone have an idea what I might be doing wrong?

bluemonkey
  • 41
  • 1
  • 5

1 Answers1

1

If you have a look at the last version of the FXMLExporter class from the 3DViewer project on OpenJFX, you will see that for materials only the diffuse color is exported:

if (PhongMaterial.class.isAssignableFrom(aClass)) {
    res.add(new Property(aClass.getMethod("getDiffuseColor"), "diffuseColor"));
}

The same happens in the project you mentioned.

You can add this line:

res.add(new Property(aClass.getMethod("getDiffuseMap"), "diffuseMap"));

to getProperties():

if (PhongMaterial.class.isAssignableFrom(aClass)) {
    res.add(new Property(aClass.getMethod("getDiffuseColor"), "diffuseColor"));
    res.add(new Property(aClass.getMethod("getDiffuseMap"), "diffuseMap"));
}

So when you export your 3D shape, this will be added to the fxml file:

<Box id="box" width="100.0" height="100.0" depth="100.0">
  <material>
    <PhongMaterial diffuseColor="0xffffffff">
      <diffuseMap>
        <Image/>
      </diffuseMap>
    </PhongMaterial>
  </material>
</Box>

We need to export also the image url. This can be done at the exportToFXML method.

Since the Image from the diffuse map doesn't store any path, the trick is to save the image to the same path where the fxml is exported. This is a quick implementation:

private FXML exportToFXML(Object object) {
    ...

    for (Property property : properties) {
        try {
            Object[] parameters = new Object[property.getter.getParameterTypes().length];
            Object value = property.getter.invoke(object, parameters);
            if (value != null) {
                ...
                } else if (value instanceof Image) {
                    FXML container = fxml.addContainer(property.name);
                    FXML fxmlImage=exportToFXML(value);
                    container.addChild(fxmlImage);
                    exportImage((Image)value,"image.png");
                    fxmlImage.addProperty("url","@image.png");
                } else {
                    FXML container = fxml.addContainer(property.name);
                    container.addChild(exportToFXML(value));
                }
            }
        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
            Logger.getLogger(FXMLExporter.class.getName()).
                    log(Level.SEVERE, null, ex);
        }
    }

    return fxml;
}

private void exportImage(Image image, String fileName){
    try {
        ImageIO.write(SwingFXUtils.fromFXImage(image, null), "png", new File(fileName));
    } catch (IOException ex) { 
        System.out.println("Error saving image");
    }
}

If you run it now, this is what you'll get:

<Box id="box" width="100.0" height="100.0" depth="100.0">
  <material>
    <PhongMaterial diffuseColor="0xffffffff">
      <diffuseMap>
        <Image url="@image.png"/>
      </diffuseMap>
    </PhongMaterial>
  </material>
</Box>
José Pereda
  • 44,311
  • 7
  • 104
  • 132
  • Thank you very much for your suggestions. I encountered a few issues. I defined each face of my two cubes as a separate TriangleMesh, thinking that eventually I want to be able to distinguish each face when selecting objects in the scene. I have assigned the same assigned the same material to each face of my two cubes, the export tries to write the image file 12 times. It seems there should be a way to convey to the model definition that all the images are the same. – bluemonkey Apr 15 '15 at 02:44
  • Even in the case you have several 3D shapes, but with the same material, you could implement some checking to avoid exporting the image all over again. If you have different textures, you'll need to add some counter to use different images. As I said, it was a quick implementation, so you can work on the details. – José Pereda Apr 15 '15 at 11:33
  • I agree that I can keep track of the different images. The real problem is as I described in the edits to my original post... it isn't clear how to control where the image goes and the import does not work anymore. – bluemonkey Apr 17 '15 at 02:03